blob: b2ad83e6f91ed82d3957a0bcfd6081b3fb8a0fb7 [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
Stephan Pleinesf63bde82024-01-13 15:59:33 -080021namespace frc971::codelab::testing {
Parker Schuh18dbbb42017-10-18 21:45:33 -070022
Austin Schuh9fe68f72019-08-10 19:32:03 -070023namespace chrono = ::std::chrono;
24using aos::monotonic_clock;
25
Parker Schuh18dbbb42017-10-18 21:45:33 -070026// Class which simulates stuff and sends out queue messages with the
27// position.
28class BasicSimulation {
29 public:
Austin Schuh9fe68f72019-08-10 19:32:03 -070030 BasicSimulation(::aos::EventLoop *event_loop, chrono::nanoseconds dt)
31 : event_loop_(event_loop),
Alex Perrycb7da4b2019-08-28 19:35:56 -070032 position_sender_(event_loop_->MakeSender<Position>("/codelab")),
33 status_fetcher_(event_loop_->MakeFetcher<Status>("/codelab")),
34 output_fetcher_(event_loop_->MakeFetcher<Output>("/codelab")) {
Austin Schuh9fe68f72019-08-10 19:32:03 -070035 event_loop_->AddPhasedLoop(
36 [this](int) {
37 // Skip this the first time.
38 if (!first_) {
39 Simulate();
40 }
41 first_ = false;
42 SendPositionMessage();
43 },
44 dt);
45 }
Parker Schuh18dbbb42017-10-18 21:45:33 -070046
47 // Sends a queue message with the position data.
48 void SendPositionMessage() {
Alex Perrycb7da4b2019-08-28 19:35:56 -070049 auto builder = position_sender_.MakeBuilder();
Parker Schuh18dbbb42017-10-18 21:45:33 -070050
Alex Perrycb7da4b2019-08-28 19:35:56 -070051 Position::Builder position_builder = builder.MakeBuilder<Position>();
Parker Schuh18dbbb42017-10-18 21:45:33 -070052
Alex Perrycb7da4b2019-08-28 19:35:56 -070053 position_builder.add_limit_sensor(limit_sensor_);
54
milind1f1dca32021-07-03 13:50:07 -070055 EXPECT_EQ(builder.Send(position_builder.Finish()),
56 aos::RawSender::Error::kOk);
Parker Schuh18dbbb42017-10-18 21:45:33 -070057 }
58
Sabina Leaver7d9220d2021-06-30 20:55:15 -070059 // This is a helper function that is used in the tests to check
60 // if the output of the test is equal to the expected output.
61 // It takes in two expected values and ompares them to the values
62 // it recieves from the code.
Parker Schuh18dbbb42017-10-18 21:45:33 -070063 void VerifyResults(double voltage, bool status) {
Austin Schuh9fe68f72019-08-10 19:32:03 -070064 output_fetcher_.Fetch();
65 status_fetcher_.Fetch();
Parker Schuh18dbbb42017-10-18 21:45:33 -070066
Austin Schuh9fe68f72019-08-10 19:32:03 -070067 ASSERT_TRUE(output_fetcher_.get() != nullptr);
68 ASSERT_TRUE(status_fetcher_.get() != nullptr);
Parker Schuh18dbbb42017-10-18 21:45:33 -070069
Alex Perrycb7da4b2019-08-28 19:35:56 -070070 EXPECT_EQ(output_fetcher_->intake_voltage(), voltage);
71 EXPECT_EQ(status_fetcher_->intake_complete(), status);
Parker Schuh18dbbb42017-10-18 21:45:33 -070072 }
73
74 void set_limit_sensor(bool value) { limit_sensor_ = value; }
75
76 // Simulates basic control loop for a single timestep.
Austin Schuh9fe68f72019-08-10 19:32:03 -070077 void Simulate() { EXPECT_TRUE(output_fetcher_.Fetch()); }
Parker Schuh18dbbb42017-10-18 21:45:33 -070078
79 private:
Austin Schuh9fe68f72019-08-10 19:32:03 -070080 ::aos::EventLoop *event_loop_;
81
Alex Perrycb7da4b2019-08-28 19:35:56 -070082 ::aos::Sender<Position> position_sender_;
83 ::aos::Fetcher<Status> status_fetcher_;
84 ::aos::Fetcher<Output> output_fetcher_;
Austin Schuh9fe68f72019-08-10 19:32:03 -070085
Parker Schuh18dbbb42017-10-18 21:45:33 -070086 bool limit_sensor_ = false;
Austin Schuh9fe68f72019-08-10 19:32:03 -070087
88 bool first_ = true;
Parker Schuh18dbbb42017-10-18 21:45:33 -070089};
90
James Kuszmaul61750662021-06-21 21:32:33 -070091class BasicControlLoopTest : public ::frc971::testing::ControlLoopTest {
Parker Schuh18dbbb42017-10-18 21:45:33 -070092 public:
93 BasicControlLoopTest()
James Kuszmaul61750662021-06-21 21:32:33 -070094 : ::frc971::testing::ControlLoopTest(
Austin Schuhc5fa6d92022-02-25 14:36:28 -080095 aos::configuration::ReadConfig("frc971/codelab/aos_config.json"),
Alex Perrycb7da4b2019-08-28 19:35:56 -070096 chrono::microseconds(5050)),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080097 test_event_loop_(MakeEventLoop("test")),
Alex Perrycb7da4b2019-08-28 19:35:56 -070098 goal_sender_(test_event_loop_->MakeSender<Goal>("/codelab")),
Austin Schuh9fe68f72019-08-10 19:32:03 -070099
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800100 basic_event_loop_(MakeEventLoop("basic")),
Alex Perrycb7da4b2019-08-28 19:35:56 -0700101 basic_(basic_event_loop_.get(), "/codelab"),
Austin Schuh9fe68f72019-08-10 19:32:03 -0700102
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800103 basic_simulation_event_loop_(MakeEventLoop("simulation")),
Austin Schuh9fe68f72019-08-10 19:32:03 -0700104 basic_simulation_(basic_simulation_event_loop_.get(), dt()) {
Parker Schuh18dbbb42017-10-18 21:45:33 -0700105 set_team_id(control_loops::testing::kTeamNumber);
James Kuszmaul78e29ac2020-07-28 21:07:03 -0700106 SetEnabled(true);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700107 }
108
Austin Schuh9fe68f72019-08-10 19:32:03 -0700109 ::std::unique_ptr<::aos::EventLoop> test_event_loop_;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700110 ::aos::Sender<Goal> goal_sender_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700111
Austin Schuh9fe68f72019-08-10 19:32:03 -0700112 ::std::unique_ptr<::aos::EventLoop> basic_event_loop_;
113 Basic basic_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700114
Austin Schuh9fe68f72019-08-10 19:32:03 -0700115 ::std::unique_ptr<::aos::EventLoop> basic_simulation_event_loop_;
Parker Schuh18dbbb42017-10-18 21:45:33 -0700116 BasicSimulation basic_simulation_;
117};
118
119// Tests that when the motor has finished intaking it stops.
120TEST_F(BasicControlLoopTest, IntakeLimitTransitionsToTrue) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700121 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700122 auto builder = goal_sender_.MakeBuilder();
123 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
124 goal_builder.add_intake(true);
Philipp Schrader790cb542023-07-05 21:06:52 -0700125 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700126 }
127
Parker Schuh18dbbb42017-10-18 21:45:33 -0700128 basic_simulation_.set_limit_sensor(false);
129
Austin Schuh9fe68f72019-08-10 19:32:03 -0700130 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700131
132 basic_simulation_.VerifyResults(12.0, false);
133
Austin Schuh9fe68f72019-08-10 19:32:03 -0700134 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700135 auto builder = goal_sender_.MakeBuilder();
136 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
137 goal_builder.add_intake(true);
Philipp Schrader790cb542023-07-05 21:06:52 -0700138 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700139 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700140 basic_simulation_.set_limit_sensor(true);
141
Austin Schuh9fe68f72019-08-10 19:32:03 -0700142 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700143
144 basic_simulation_.VerifyResults(0.0, true);
145}
146
147// Tests that the intake goes on if the sensor is not pressed
148// and intake is requested.
149TEST_F(BasicControlLoopTest, IntakeLimitNotSet) {
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);
Philipp Schrader790cb542023-07-05 21:06:52 -0700154 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700155 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700156 basic_simulation_.set_limit_sensor(false);
157
Austin Schuh9fe68f72019-08-10 19:32:03 -0700158 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700159
160 basic_simulation_.VerifyResults(12.0, false);
161}
162
163// Tests that the intake is off if no intake is requested,
164// even if the limit sensor is off.
165TEST_F(BasicControlLoopTest, NoIntakeLimitNotSet) {
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(false);
Philipp Schrader790cb542023-07-05 21:06:52 -0700170 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
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(0.0, false);
177}
178
179// Tests that the intake is off even if the limit sensor
180// is pressed and intake is requested.
181TEST_F(BasicControlLoopTest, IntakeLimitSet) {
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(true);
Philipp Schrader790cb542023-07-05 21:06:52 -0700186 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700187 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700188 basic_simulation_.set_limit_sensor(true);
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, true);
193}
194
195// Tests that the intake is off if no intake is requested,
196TEST_F(BasicControlLoopTest, NoIntakeLimitSet) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700197 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700198 auto builder = goal_sender_.MakeBuilder();
199 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
200 goal_builder.add_intake(false);
Philipp Schrader790cb542023-07-05 21:06:52 -0700201 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700202 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700203 basic_simulation_.set_limit_sensor(true);
204
Austin Schuh9fe68f72019-08-10 19:32:03 -0700205 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700206
207 basic_simulation_.VerifyResults(0.0, false);
208}
209
210// Tests that the control loop handles things properly if no goal is set.
211TEST_F(BasicControlLoopTest, NoGoalSet) {
212 basic_simulation_.set_limit_sensor(true);
213
Austin Schuh9fe68f72019-08-10 19:32:03 -0700214 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700215
216 basic_simulation_.VerifyResults(0.0, false);
217}
218
219// Tests that the control loop handles things properly if disabled.
Sabina Leaver7d9220d2021-06-30 20:55:15 -0700220// Note: "output" will be null when the robot is disabled. This is
221// a tricky test to get to pass, it should pass at first but fail
222// as you add more code.
Parker Schuh18dbbb42017-10-18 21:45:33 -0700223TEST_F(BasicControlLoopTest, Disabled) {
224 basic_simulation_.set_limit_sensor(true);
225
Austin Schuh9fe68f72019-08-10 19:32:03 -0700226 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700227 auto builder = goal_sender_.MakeBuilder();
228 Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
229 goal_builder.add_intake(true);
Philipp Schrader790cb542023-07-05 21:06:52 -0700230 ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700231 }
Parker Schuh18dbbb42017-10-18 21:45:33 -0700232
Austin Schuh9fe68f72019-08-10 19:32:03 -0700233 SetEnabled(false);
234 RunFor(dt() * 2);
Parker Schuh18dbbb42017-10-18 21:45:33 -0700235
236 basic_simulation_.VerifyResults(0.0, false);
237}
238
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800239} // namespace frc971::codelab::testing