blob: e9820bc6665ca9f6ea913f0ba4dbfb20e3e427d0 [file] [log] [blame]
Sabina Leaver7d9220d2021-06-30 20:55:15 -07001// In this file, you can view the tests that are being run to determine
2// if the code works properly in different situations.
3
Parker Schuh18dbbb42017-10-18 21:45:33 -07004#include "frc971/codelab/basic.h"
5
6#include <unistd.h>
7
8#include <chrono>
9#include <memory>
10
Philipp Schrader790cb542023-07-05 21:06:52 -070011#include "gtest/gtest.h"
12
Alex Perrycb7da4b2019-08-28 19:35:56 -070013#include "aos/events/shm_event_loop.h"
James Kuszmaul78e29ac2020-07-28 21:07:03 -070014#include "frc971/codelab/basic_goal_generated.h"
15#include "frc971/codelab/basic_output_generated.h"
16#include "frc971/codelab/basic_position_generated.h"
17#include "frc971/codelab/basic_status_generated.h"
James Kuszmaul61750662021-06-21 21:32:33 -070018#include "frc971/control_loops/control_loop_test.h"
Parker Schuh18dbbb42017-10-18 21:45:33 -070019#include "frc971/control_loops/team_number_test_environment.h"
Parker Schuh18dbbb42017-10-18 21:45:33 -070020
21namespace frc971 {
22namespace codelab {
23namespace testing {
24
Austin Schuh9fe68f72019-08-10 19:32:03 -070025namespace chrono = ::std::chrono;
26using aos::monotonic_clock;
27
Parker Schuh18dbbb42017-10-18 21:45:33 -070028// Class which simulates stuff and sends out queue messages with the
29// position.
30class BasicSimulation {
31 public:
Austin Schuh9fe68f72019-08-10 19:32:03 -070032 BasicSimulation(::aos::EventLoop *event_loop, chrono::nanoseconds dt)
33 : event_loop_(event_loop),
Alex Perrycb7da4b2019-08-28 19:35:56 -070034 position_sender_(event_loop_->MakeSender<Position>("/codelab")),
35 status_fetcher_(event_loop_->MakeFetcher<Status>("/codelab")),
36 output_fetcher_(event_loop_->MakeFetcher<Output>("/codelab")) {
Austin Schuh9fe68f72019-08-10 19:32:03 -070037 event_loop_->AddPhasedLoop(
38 [this](int) {
39 // Skip this the first time.
40 if (!first_) {
41 Simulate();
42 }
43 first_ = false;
44 SendPositionMessage();
45 },
46 dt);
47 }
Parker Schuh18dbbb42017-10-18 21:45:33 -070048
49 // Sends a queue message with the position data.
50 void SendPositionMessage() {
Alex Perrycb7da4b2019-08-28 19:35:56 -070051 auto builder = position_sender_.MakeBuilder();
Parker Schuh18dbbb42017-10-18 21:45:33 -070052
Alex Perrycb7da4b2019-08-28 19:35:56 -070053 Position::Builder position_builder = builder.MakeBuilder<Position>();
Parker Schuh18dbbb42017-10-18 21:45:33 -070054
Alex Perrycb7da4b2019-08-28 19:35:56 -070055 position_builder.add_limit_sensor(limit_sensor_);
56
milind1f1dca32021-07-03 13:50:07 -070057 EXPECT_EQ(builder.Send(position_builder.Finish()),
58 aos::RawSender::Error::kOk);
Parker Schuh18dbbb42017-10-18 21:45:33 -070059 }
60
Sabina Leaver7d9220d2021-06-30 20:55:15 -070061 // This is a helper function that is used in the tests to check
62 // if the output of the test is equal to the expected output.
63 // It takes in two expected values and ompares them to the values
64 // it recieves from the code.
Parker Schuh18dbbb42017-10-18 21:45:33 -070065 void VerifyResults(double voltage, bool status) {
Austin Schuh9fe68f72019-08-10 19:32:03 -070066 output_fetcher_.Fetch();
67 status_fetcher_.Fetch();
Parker Schuh18dbbb42017-10-18 21:45:33 -070068
Austin Schuh9fe68f72019-08-10 19:32:03 -070069 ASSERT_TRUE(output_fetcher_.get() != nullptr);
70 ASSERT_TRUE(status_fetcher_.get() != nullptr);
Parker Schuh18dbbb42017-10-18 21:45:33 -070071
Alex Perrycb7da4b2019-08-28 19:35:56 -070072 EXPECT_EQ(output_fetcher_->intake_voltage(), voltage);
73 EXPECT_EQ(status_fetcher_->intake_complete(), status);
Parker Schuh18dbbb42017-10-18 21:45:33 -070074 }
75
76 void set_limit_sensor(bool value) { limit_sensor_ = value; }
77
78 // Simulates basic control loop for a single timestep.
Austin Schuh9fe68f72019-08-10 19:32:03 -070079 void Simulate() { EXPECT_TRUE(output_fetcher_.Fetch()); }
Parker Schuh18dbbb42017-10-18 21:45:33 -070080
81 private:
Austin Schuh9fe68f72019-08-10 19:32:03 -070082 ::aos::EventLoop *event_loop_;
83
Alex Perrycb7da4b2019-08-28 19:35:56 -070084 ::aos::Sender<Position> position_sender_;
85 ::aos::Fetcher<Status> status_fetcher_;
86 ::aos::Fetcher<Output> output_fetcher_;
Austin Schuh9fe68f72019-08-10 19:32:03 -070087
Parker Schuh18dbbb42017-10-18 21:45:33 -070088 bool limit_sensor_ = false;
Austin Schuh9fe68f72019-08-10 19:32:03 -070089
90 bool first_ = true;
Parker Schuh18dbbb42017-10-18 21:45:33 -070091};
92
James Kuszmaul61750662021-06-21 21:32:33 -070093class BasicControlLoopTest : public ::frc971::testing::ControlLoopTest {
Parker Schuh18dbbb42017-10-18 21:45:33 -070094 public:
95 BasicControlLoopTest()
James Kuszmaul61750662021-06-21 21:32:33 -070096 : ::frc971::testing::ControlLoopTest(
Austin Schuhc5fa6d92022-02-25 14:36:28 -080097 aos::configuration::ReadConfig("frc971/codelab/aos_config.json"),
Alex Perrycb7da4b2019-08-28 19:35:56 -070098 chrono::microseconds(5050)),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080099 test_event_loop_(MakeEventLoop("test")),
Alex Perrycb7da4b2019-08-28 19:35:56 -0700100 goal_sender_(test_event_loop_->MakeSender<Goal>("/codelab")),
Austin Schuh9fe68f72019-08-10 19:32:03 -0700101
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800102 basic_event_loop_(MakeEventLoop("basic")),
Alex Perrycb7da4b2019-08-28 19:35:56 -0700103 basic_(basic_event_loop_.get(), "/codelab"),
Austin Schuh9fe68f72019-08-10 19:32:03 -0700104
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800105 basic_simulation_event_loop_(MakeEventLoop("simulation")),
Austin Schuh9fe68f72019-08-10 19:32:03 -0700106 basic_simulation_(basic_simulation_event_loop_.get(), dt()) {
Parker Schuh18dbbb42017-10-18 21:45:33 -0700107 set_team_id(control_loops::testing::kTeamNumber);
James Kuszmaul78e29ac2020-07-28 21:07:03 -0700108 SetEnabled(true);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700109 }
110
Austin Schuh9fe68f72019-08-10 19:32:03 -0700111 ::std::unique_ptr<::aos::EventLoop> test_event_loop_;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700112 ::aos::Sender<Goal> goal_sender_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700113
Austin Schuh9fe68f72019-08-10 19:32:03 -0700114 ::std::unique_ptr<::aos::EventLoop> basic_event_loop_;
115 Basic basic_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700116
Austin Schuh9fe68f72019-08-10 19:32:03 -0700117 ::std::unique_ptr<::aos::EventLoop> basic_simulation_event_loop_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700118 BasicSimulation basic_simulation_;
119};
120
121// Tests that when the motor has finished intaking it stops.
122TEST_F(BasicControlLoopTest, IntakeLimitTransitionsToTrue) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700123 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700124 auto builder = goal_sender_.MakeBuilder();
125 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
126 goal_builder.add_intake(true);
Philipp Schrader790cb542023-07-05 21:06:52 -0700127 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700128 }
129
Parker Schuh18dbbb42017-10-18 21:45:33 -0700130 basic_simulation_.set_limit_sensor(false);
131
Austin Schuh9fe68f72019-08-10 19:32:03 -0700132 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700133
134 basic_simulation_.VerifyResults(12.0, false);
135
Austin Schuh9fe68f72019-08-10 19:32:03 -0700136 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700137 auto builder = goal_sender_.MakeBuilder();
138 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
139 goal_builder.add_intake(true);
Philipp Schrader790cb542023-07-05 21:06:52 -0700140 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700141 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700142 basic_simulation_.set_limit_sensor(true);
143
Austin Schuh9fe68f72019-08-10 19:32:03 -0700144 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700145
146 basic_simulation_.VerifyResults(0.0, true);
147}
148
149// Tests that the intake goes on if the sensor is not pressed
150// and intake is requested.
151TEST_F(BasicControlLoopTest, IntakeLimitNotSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700152 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700153 auto builder = goal_sender_.MakeBuilder();
154 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
155 goal_builder.add_intake(true);
Philipp Schrader790cb542023-07-05 21:06:52 -0700156 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700157 }
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(12.0, false);
163}
164
165// Tests that the intake is off if no intake is requested,
166// even if the limit sensor is off.
167TEST_F(BasicControlLoopTest, NoIntakeLimitNotSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700168 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700169 auto builder = goal_sender_.MakeBuilder();
170 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
171 goal_builder.add_intake(false);
Philipp Schrader790cb542023-07-05 21:06:52 -0700172 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700173 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700174 basic_simulation_.set_limit_sensor(false);
175
Austin Schuh9fe68f72019-08-10 19:32:03 -0700176 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700177
178 basic_simulation_.VerifyResults(0.0, false);
179}
180
181// Tests that the intake is off even if the limit sensor
182// is pressed and intake is requested.
183TEST_F(BasicControlLoopTest, IntakeLimitSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700184 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700185 auto builder = goal_sender_.MakeBuilder();
186 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
187 goal_builder.add_intake(true);
Philipp Schrader790cb542023-07-05 21:06:52 -0700188 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700189 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700190 basic_simulation_.set_limit_sensor(true);
191
Austin Schuh9fe68f72019-08-10 19:32:03 -0700192 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700193
194 basic_simulation_.VerifyResults(0.0, true);
195}
196
197// Tests that the intake is off if no intake is requested,
198TEST_F(BasicControlLoopTest, NoIntakeLimitSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700199 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700200 auto builder = goal_sender_.MakeBuilder();
201 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
202 goal_builder.add_intake(false);
Philipp Schrader790cb542023-07-05 21:06:52 -0700203 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700204 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700205 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 no goal is set.
213TEST_F(BasicControlLoopTest, NoGoalSet) {
214 basic_simulation_.set_limit_sensor(true);
215
Austin Schuh9fe68f72019-08-10 19:32:03 -0700216 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700217
218 basic_simulation_.VerifyResults(0.0, false);
219}
220
221// Tests that the control loop handles things properly if disabled.
Sabina Leaver7d9220d2021-06-30 20:55:15 -0700222// Note: "output" will be null when the robot is disabled. This is
223// a tricky test to get to pass, it should pass at first but fail
224// as you add more code.
Parker Schuh18dbbb42017-10-18 21:45:33 -0700225TEST_F(BasicControlLoopTest, Disabled) {
226 basic_simulation_.set_limit_sensor(true);
227
Austin Schuh9fe68f72019-08-10 19:32:03 -0700228 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700229 auto builder = goal_sender_.MakeBuilder();
230 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
231 goal_builder.add_intake(true);
Philipp Schrader790cb542023-07-05 21:06:52 -0700232 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700233 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700234
Austin Schuh9fe68f72019-08-10 19:32:03 -0700235 SetEnabled(false);
236 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700237
238 basic_simulation_.VerifyResults(0.0, false);
239}
240
241} // namespace testing
242} // namespace codelab
243} // namespace frc971