blob: 9b22705298aaa17673aa20958dd3908e2dde4d31 [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
Alex Perrycb7da4b2019-08-28 19:35:56 -07008#include "aos/events/shm_event_loop.h"
James Kuszmaul78e29ac2020-07-28 21:07:03 -07009#include "frc971/codelab/basic_goal_generated.h"
10#include "frc971/codelab/basic_output_generated.h"
11#include "frc971/codelab/basic_position_generated.h"
12#include "frc971/codelab/basic_status_generated.h"
James Kuszmaul61750662021-06-21 21:32:33 -070013#include "frc971/control_loops/control_loop_test.h"
Parker Schuh18dbbb42017-10-18 21:45:33 -070014#include "frc971/control_loops/team_number_test_environment.h"
15#include "gtest/gtest.h"
16
17namespace frc971 {
18namespace codelab {
19namespace testing {
20
Austin Schuh9fe68f72019-08-10 19:32:03 -070021namespace chrono = ::std::chrono;
22using aos::monotonic_clock;
23
Parker Schuh18dbbb42017-10-18 21:45:33 -070024// Class which simulates stuff and sends out queue messages with the
25// position.
26class BasicSimulation {
27 public:
Austin Schuh9fe68f72019-08-10 19:32:03 -070028 BasicSimulation(::aos::EventLoop *event_loop, chrono::nanoseconds dt)
29 : event_loop_(event_loop),
Alex Perrycb7da4b2019-08-28 19:35:56 -070030 position_sender_(event_loop_->MakeSender<Position>("/codelab")),
31 status_fetcher_(event_loop_->MakeFetcher<Status>("/codelab")),
32 output_fetcher_(event_loop_->MakeFetcher<Output>("/codelab")) {
Austin Schuh9fe68f72019-08-10 19:32:03 -070033 event_loop_->AddPhasedLoop(
34 [this](int) {
35 // Skip this the first time.
36 if (!first_) {
37 Simulate();
38 }
39 first_ = false;
40 SendPositionMessage();
41 },
42 dt);
43 }
Parker Schuh18dbbb42017-10-18 21:45:33 -070044
45 // Sends a queue message with the position data.
46 void SendPositionMessage() {
Alex Perrycb7da4b2019-08-28 19:35:56 -070047 auto builder = position_sender_.MakeBuilder();
Parker Schuh18dbbb42017-10-18 21:45:33 -070048
Alex Perrycb7da4b2019-08-28 19:35:56 -070049 Position::Builder position_builder = builder.MakeBuilder<Position>();
Parker Schuh18dbbb42017-10-18 21:45:33 -070050
Alex Perrycb7da4b2019-08-28 19:35:56 -070051 position_builder.add_limit_sensor(limit_sensor_);
52
53 builder.Send(position_builder.Finish());
Parker Schuh18dbbb42017-10-18 21:45:33 -070054 }
55
56 void VerifyResults(double voltage, bool status) {
Austin Schuh9fe68f72019-08-10 19:32:03 -070057 output_fetcher_.Fetch();
58 status_fetcher_.Fetch();
Parker Schuh18dbbb42017-10-18 21:45:33 -070059
Austin Schuh9fe68f72019-08-10 19:32:03 -070060 ASSERT_TRUE(output_fetcher_.get() != nullptr);
61 ASSERT_TRUE(status_fetcher_.get() != nullptr);
Parker Schuh18dbbb42017-10-18 21:45:33 -070062
Alex Perrycb7da4b2019-08-28 19:35:56 -070063 EXPECT_EQ(output_fetcher_->intake_voltage(), voltage);
64 EXPECT_EQ(status_fetcher_->intake_complete(), status);
Parker Schuh18dbbb42017-10-18 21:45:33 -070065 }
66
67 void set_limit_sensor(bool value) { limit_sensor_ = value; }
68
69 // Simulates basic control loop for a single timestep.
Austin Schuh9fe68f72019-08-10 19:32:03 -070070 void Simulate() { EXPECT_TRUE(output_fetcher_.Fetch()); }
Parker Schuh18dbbb42017-10-18 21:45:33 -070071
72 private:
Austin Schuh9fe68f72019-08-10 19:32:03 -070073 ::aos::EventLoop *event_loop_;
74
Alex Perrycb7da4b2019-08-28 19:35:56 -070075 ::aos::Sender<Position> position_sender_;
76 ::aos::Fetcher<Status> status_fetcher_;
77 ::aos::Fetcher<Output> output_fetcher_;
Austin Schuh9fe68f72019-08-10 19:32:03 -070078
Parker Schuh18dbbb42017-10-18 21:45:33 -070079 bool limit_sensor_ = false;
Austin Schuh9fe68f72019-08-10 19:32:03 -070080
81 bool first_ = true;
Parker Schuh18dbbb42017-10-18 21:45:33 -070082};
83
James Kuszmaul61750662021-06-21 21:32:33 -070084class BasicControlLoopTest : public ::frc971::testing::ControlLoopTest {
Parker Schuh18dbbb42017-10-18 21:45:33 -070085 public:
86 BasicControlLoopTest()
James Kuszmaul61750662021-06-21 21:32:33 -070087 : ::frc971::testing::ControlLoopTest(
James Kuszmaul78e29ac2020-07-28 21:07:03 -070088 aos::configuration::ReadConfig("frc971/codelab/config.json"),
Alex Perrycb7da4b2019-08-28 19:35:56 -070089 chrono::microseconds(5050)),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080090 test_event_loop_(MakeEventLoop("test")),
Alex Perrycb7da4b2019-08-28 19:35:56 -070091 goal_sender_(test_event_loop_->MakeSender<Goal>("/codelab")),
Austin Schuh9fe68f72019-08-10 19:32:03 -070092
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080093 basic_event_loop_(MakeEventLoop("basic")),
Alex Perrycb7da4b2019-08-28 19:35:56 -070094 basic_(basic_event_loop_.get(), "/codelab"),
Austin Schuh9fe68f72019-08-10 19:32:03 -070095
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080096 basic_simulation_event_loop_(MakeEventLoop("simulation")),
Austin Schuh9fe68f72019-08-10 19:32:03 -070097 basic_simulation_(basic_simulation_event_loop_.get(), dt()) {
Parker Schuh18dbbb42017-10-18 21:45:33 -070098 set_team_id(control_loops::testing::kTeamNumber);
James Kuszmaul78e29ac2020-07-28 21:07:03 -070099 SetEnabled(true);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700100 }
101
Austin Schuh9fe68f72019-08-10 19:32:03 -0700102 ::std::unique_ptr<::aos::EventLoop> test_event_loop_;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700103 ::aos::Sender<Goal> goal_sender_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700104
Austin Schuh9fe68f72019-08-10 19:32:03 -0700105 ::std::unique_ptr<::aos::EventLoop> basic_event_loop_;
106 Basic basic_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700107
Austin Schuh9fe68f72019-08-10 19:32:03 -0700108 ::std::unique_ptr<::aos::EventLoop> basic_simulation_event_loop_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700109 BasicSimulation basic_simulation_;
110};
111
112// Tests that when the motor has finished intaking it stops.
113TEST_F(BasicControlLoopTest, IntakeLimitTransitionsToTrue) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700114 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700115 auto builder = goal_sender_.MakeBuilder();
116 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
117 goal_builder.add_intake(true);
118 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700119 }
120
Parker Schuh18dbbb42017-10-18 21:45:33 -0700121 basic_simulation_.set_limit_sensor(false);
122
Austin Schuh9fe68f72019-08-10 19:32:03 -0700123 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700124
125 basic_simulation_.VerifyResults(12.0, false);
126
Austin Schuh9fe68f72019-08-10 19:32:03 -0700127 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700128 auto builder = goal_sender_.MakeBuilder();
129 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
130 goal_builder.add_intake(true);
131 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700132 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700133 basic_simulation_.set_limit_sensor(true);
134
Austin Schuh9fe68f72019-08-10 19:32:03 -0700135 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700136
137 basic_simulation_.VerifyResults(0.0, true);
138}
139
140// Tests that the intake goes on if the sensor is not pressed
141// and intake is requested.
142TEST_F(BasicControlLoopTest, IntakeLimitNotSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700143 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700144 auto builder = goal_sender_.MakeBuilder();
145 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
146 goal_builder.add_intake(true);
147 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700148 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700149 basic_simulation_.set_limit_sensor(false);
150
Austin Schuh9fe68f72019-08-10 19:32:03 -0700151 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700152
153 basic_simulation_.VerifyResults(12.0, false);
154}
155
156// Tests that the intake is off if no intake is requested,
157// even if the limit sensor is off.
158TEST_F(BasicControlLoopTest, NoIntakeLimitNotSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700159 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700160 auto builder = goal_sender_.MakeBuilder();
161 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
162 goal_builder.add_intake(false);
163 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700164 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700165 basic_simulation_.set_limit_sensor(false);
166
Austin Schuh9fe68f72019-08-10 19:32:03 -0700167 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700168
169 basic_simulation_.VerifyResults(0.0, false);
170}
171
172// Tests that the intake is off even if the limit sensor
173// is pressed and intake is requested.
174TEST_F(BasicControlLoopTest, IntakeLimitSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700175 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700176 auto builder = goal_sender_.MakeBuilder();
177 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
178 goal_builder.add_intake(true);
179 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700180 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700181 basic_simulation_.set_limit_sensor(true);
182
Austin Schuh9fe68f72019-08-10 19:32:03 -0700183 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700184
185 basic_simulation_.VerifyResults(0.0, true);
186}
187
188// Tests that the intake is off if no intake is requested,
189TEST_F(BasicControlLoopTest, NoIntakeLimitSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700190 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700191 auto builder = goal_sender_.MakeBuilder();
192 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
193 goal_builder.add_intake(false);
194 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700195 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700196 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 no goal is set.
204TEST_F(BasicControlLoopTest, NoGoalSet) {
205 basic_simulation_.set_limit_sensor(true);
206
Austin Schuh9fe68f72019-08-10 19:32:03 -0700207 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700208
209 basic_simulation_.VerifyResults(0.0, false);
210}
211
212// Tests that the control loop handles things properly if disabled.
213TEST_F(BasicControlLoopTest, Disabled) {
214 basic_simulation_.set_limit_sensor(true);
215
Austin Schuh9fe68f72019-08-10 19:32:03 -0700216 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700217 auto builder = goal_sender_.MakeBuilder();
218 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
219 goal_builder.add_intake(true);
220 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700221 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700222
Austin Schuh9fe68f72019-08-10 19:32:03 -0700223 SetEnabled(false);
224 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700225
226 basic_simulation_.VerifyResults(0.0, false);
227}
228
229} // namespace testing
230} // namespace codelab
231} // namespace frc971