blob: 8b6ba099fd667132c1d1f985181dc33e6cfa8b08 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#ifndef AOS_CONTROLS_CONTROL_LOOP_TEST_H_
2#define AOS_CONTROLS_CONTROL_LOOP_TEST_H_
Brian Silverman65e49702014-04-30 17:36:40 -07003
Austin Schuh2001aa42018-10-29 22:57:02 -07004#include <chrono>
Austin Schuh5f1cc5c2019-12-01 18:01:11 -08005#include <string_view>
Austin Schuh2001aa42018-10-29 22:57:02 -07006
Philipp Schrader790cb542023-07-05 21:06:52 -07007#include "glog/logging.h"
8#include "gtest/gtest.h"
9
Alex Perrycb7da4b2019-08-28 19:35:56 -070010#include "aos/events/simulated_event_loop.h"
11#include "aos/flatbuffers.h"
12#include "aos/json_to_flatbuffer.h"
Austin Schuh0debde12022-08-17 16:25:17 -070013#include "aos/network/testing_time_converter.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070014#include "aos/testing/test_logging.h"
John Park33858a32018-09-28 23:05:48 -070015#include "aos/time/time.h"
James Kuszmaul7077d342021-06-09 20:23:58 -070016#include "frc971/input/joystick_state_generated.h"
17#include "frc971/input/robot_state_generated.h"
Brian Silverman65e49702014-04-30 17:36:40 -070018
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080019namespace frc971::testing {
Brian Silverman65e49702014-04-30 17:36:40 -070020
21// Handles setting up the environment that all control loops need to actually
22// run.
23// This includes sending the queue messages and Clear()ing the queues when
24// appropriate.
25// It also includes dealing with ::aos::time.
Austin Schuh2001aa42018-10-29 22:57:02 -070026template <typename TestBaseClass>
27class ControlLoopTestTemplated : public TestBaseClass {
Brian Silverman65e49702014-04-30 17:36:40 -070028 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070029 ControlLoopTestTemplated(
James Kuszmaul61750662021-06-21 21:32:33 -070030 aos::FlatbufferDetachedBuffer<aos::Configuration> configuration,
Austin Schuh0debde12022-08-17 16:25:17 -070031 ::std::chrono::nanoseconds dt = kTimeTick,
32 std::vector<std::vector<aos::logger::BootTimestamp>> times = {})
Alex Perrycb7da4b2019-08-28 19:35:56 -070033 : configuration_(std::move(configuration)),
Austin Schuh0debde12022-08-17 16:25:17 -070034 time_converter_(
35 aos::configuration::NodesCount(&configuration_.message())),
Alex Perrycb7da4b2019-08-28 19:35:56 -070036 event_loop_factory_(&configuration_.message()),
Austin Schuh0debde12022-08-17 16:25:17 -070037 dt_(dt) {
38 event_loop_factory()->SetTimeConverter(&time_converter_);
39
40 // We need to setup the time converter before any event loop has been
41 // created. Otherwise, the event loop will read the boot uuid and we'll be
42 // unable to change it.
43 if (times.empty()) {
44 time_converter_.StartEqual();
45 } else {
46 for (const std::vector<aos::logger::BootTimestamp> &time : times) {
47 time_converter_.AddMonotonic(time);
48 }
49 }
50 robot_status_event_loop_ = MakeEventLoop(
51 "robot_status",
52 aos::configuration::MultiNode(event_loop_factory_.configuration())
53 ? aos::configuration::GetNode(event_loop_factory_.configuration(),
54 "roborio")
55 : nullptr);
James Kuszmaul61750662021-06-21 21:32:33 -070056 aos::testing::EnableTestLogging();
Austin Schuhdf6cbb12019-02-02 13:46:52 -080057 robot_state_sender_ =
Alex Perrycb7da4b2019-08-28 19:35:56 -070058 robot_status_event_loop_->MakeSender<::aos::RobotState>("/aos");
Austin Schuhdf6cbb12019-02-02 13:46:52 -080059 joystick_state_sender_ =
Alex Perrycb7da4b2019-08-28 19:35:56 -070060 robot_status_event_loop_->MakeSender<::aos::JoystickState>("/aos");
Austin Schuh2001aa42018-10-29 22:57:02 -070061
Austin Schuh9fe68f72019-08-10 19:32:03 -070062 // Schedule the robot status send 1 nanosecond before the loop runs.
63 send_robot_state_phased_loop_ = robot_status_event_loop_->AddPhasedLoop(
64 [this](int) { SendRobotState(); }, dt_,
65 dt - ::std::chrono::nanoseconds(1));
Austin Schuh2001aa42018-10-29 22:57:02 -070066
Austin Schuh9fe68f72019-08-10 19:32:03 -070067 send_joystick_state_timer_ =
68 robot_status_event_loop_->AddTimer([this]() { SendJoystickState(); });
69
70 robot_status_event_loop_->OnRun([this]() {
Philipp Schradera6712522023-07-05 20:25:11 -070071 send_joystick_state_timer_->Schedule(
Austin Schuh9fe68f72019-08-10 19:32:03 -070072 robot_status_event_loop_->monotonic_now(), dt_);
73 });
Austin Schuh2001aa42018-10-29 22:57:02 -070074 }
Austin Schuh9fe68f72019-08-10 19:32:03 -070075 virtual ~ControlLoopTestTemplated() {}
Brian Silverman65e49702014-04-30 17:36:40 -070076
Philipp Schraderf75a8bf2015-02-02 05:30:16 +000077 void set_team_id(uint16_t team_id) { team_id_ = team_id; }
78 uint16_t team_id() const { return team_id_; }
79
Ravago Jonesd51af7a2022-03-26 21:44:20 -070080 void set_alliance(aos::Alliance alliance) { alliance_ = alliance; }
81 aos::Alliance alliance() const { return alliance_; }
82
Austin Schuh9fe68f72019-08-10 19:32:03 -070083 // Sets the enabled/disabled bit and (potentially) rebroadcasts the robot
84 // state messages.
85 void SetEnabled(bool enabled) {
86 if (enabled_ != enabled) {
87 enabled_ = enabled;
88 SendJoystickState();
89 SendRobotState();
Philipp Schradera6712522023-07-05 20:25:11 -070090 send_joystick_state_timer_->Schedule(
Austin Schuh9fe68f72019-08-10 19:32:03 -070091 robot_status_event_loop_->monotonic_now(), dt_);
Austin Schuh2001aa42018-10-29 22:57:02 -070092 }
Brian Silvermane6f64ab2015-02-05 17:03:56 -050093 }
Brian Silverman65e49702014-04-30 17:36:40 -070094
Brian Silverman57cad222015-02-14 20:46:41 -050095 // Simulate a reset of the process reading sensors, which tells loops that all
96 // index counts etc will be reset.
Tyler Chatow67ddb032020-01-12 14:30:04 -080097 void SimulateSensorReset() { ++reader_pid_; }
Brian Silverman57cad222015-02-14 20:46:41 -050098
Austin Schuhe5f064d2016-03-05 17:43:51 -080099 // Sets the battery voltage in robot_state.
100 void set_battery_voltage(double battery_voltage) {
101 battery_voltage_ = battery_voltage;
102 }
103
Austin Schuh08e96eb2020-02-25 23:36:30 -0800104 ::std::unique_ptr<::aos::EventLoop> MakeEventLoop(
James Kuszmaul61750662021-06-21 21:32:33 -0700105 std::string_view name, const aos::Node *node = nullptr) {
Austin Schuh08e96eb2020-02-25 23:36:30 -0800106 return event_loop_factory_.MakeEventLoop(name, node);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700107 }
108
Austin Schuh7d87b672019-12-01 20:23:49 -0800109 void set_send_delay(std::chrono::nanoseconds send_delay) {
110 event_loop_factory_.set_send_delay(send_delay);
111 }
112
James Kuszmaul61750662021-06-21 21:32:33 -0700113 void RunFor(aos::monotonic_clock::duration duration) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700114 event_loop_factory_.RunFor(duration);
115 }
116
117 ::aos::monotonic_clock::time_point monotonic_now() {
Austin Schuha5e14192020-01-06 18:02:41 -0800118 return robot_status_event_loop_->monotonic_now();
Austin Schuh9fe68f72019-08-10 19:32:03 -0700119 }
120
121 ::std::chrono::nanoseconds dt() const { return dt_; }
122
James Kuszmaul61750662021-06-21 21:32:33 -0700123 const aos::Configuration *configuration() const {
Austin Schuh08e96eb2020-02-25 23:36:30 -0800124 return &configuration_.message();
125 }
126
James Kuszmaul61750662021-06-21 21:32:33 -0700127 aos::SimulatedEventLoopFactory *event_loop_factory() {
James Kuszmaul958b21e2020-02-26 21:51:40 -0800128 return &event_loop_factory_;
129 }
130
Austin Schuh0debde12022-08-17 16:25:17 -0700131 aos::message_bridge::TestingTimeConverter *time_converter() {
132 return &time_converter_;
133 }
134
Brian Silverman65e49702014-04-30 17:36:40 -0700135 private:
Austin Schuh9fe68f72019-08-10 19:32:03 -0700136 // Sends out all of the required queue messages.
137 void SendJoystickState() {
138 if (monotonic_now() >= kDSPacketTime + last_ds_time_ ||
139 last_enabled_ != enabled_) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700140 auto new_state = joystick_state_sender_.MakeBuilder();
141 ::aos::JoystickState::Builder builder =
142 new_state.template MakeBuilder<::aos::JoystickState>();
Austin Schuh9fe68f72019-08-10 19:32:03 -0700143
Alex Perrycb7da4b2019-08-28 19:35:56 -0700144 builder.add_fake(true);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700145
Alex Perrycb7da4b2019-08-28 19:35:56 -0700146 builder.add_enabled(enabled_);
147 builder.add_autonomous(false);
148 builder.add_team_id(team_id_);
Ravago Jonesd51af7a2022-03-26 21:44:20 -0700149 builder.add_alliance(alliance_);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700150
Ravago Jonesd51af7a2022-03-26 21:44:20 -0700151 CHECK_EQ(new_state.Send(builder.Finish()), aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700152
153 last_ds_time_ = monotonic_now();
154 last_enabled_ = enabled_;
155 }
156 }
157
158 bool last_enabled_ = false;
159
160 void SendRobotState() {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700161 auto new_state = robot_state_sender_.MakeBuilder();
Austin Schuh9fe68f72019-08-10 19:32:03 -0700162
Alex Perrycb7da4b2019-08-28 19:35:56 -0700163 ::aos::RobotState::Builder builder =
164 new_state.template MakeBuilder<::aos::RobotState>();
Austin Schuh9fe68f72019-08-10 19:32:03 -0700165
Alex Perrycb7da4b2019-08-28 19:35:56 -0700166 builder.add_reader_pid(reader_pid_);
167 builder.add_outputs_enabled(enabled_);
168 builder.add_browned_out(false);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700169
Alex Perrycb7da4b2019-08-28 19:35:56 -0700170 builder.add_is_3v3_active(true);
171 builder.add_is_5v_active(true);
172 builder.add_voltage_3v3(3.3);
173 builder.add_voltage_5v(5.0);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700174
Alex Perrycb7da4b2019-08-28 19:35:56 -0700175 builder.add_voltage_roborio_in(battery_voltage_);
176 builder.add_voltage_battery(battery_voltage_);
177
milind1f1dca32021-07-03 13:50:07 -0700178 new_state.CheckOk(new_state.Send(builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700179 }
180
181 static constexpr ::std::chrono::microseconds kTimeTick{5000};
Austin Schuh6a6f90c2016-11-25 21:36:42 -0800182 static constexpr ::std::chrono::milliseconds kDSPacketTime{20};
Brian Silvermane6f64ab2015-02-05 17:03:56 -0500183
James Kuszmaul61750662021-06-21 21:32:33 -0700184 aos::FlatbufferDetachedBuffer<aos::Configuration> configuration_;
Austin Schuh9fe68f72019-08-10 19:32:03 -0700185
Austin Schuh0debde12022-08-17 16:25:17 -0700186 aos::message_bridge::TestingTimeConverter time_converter_;
187
James Kuszmaul61750662021-06-21 21:32:33 -0700188 aos::SimulatedEventLoopFactory event_loop_factory_;
Austin Schuh9fe68f72019-08-10 19:32:03 -0700189
Alex Perrycb7da4b2019-08-28 19:35:56 -0700190 const ::std::chrono::nanoseconds dt_;
191
Philipp Schraderf75a8bf2015-02-02 05:30:16 +0000192 uint16_t team_id_ = 971;
Ravago Jonesd51af7a2022-03-26 21:44:20 -0700193 aos::Alliance alliance_ = aos::Alliance::kInvalid;
Brian Silverman57cad222015-02-14 20:46:41 -0500194 int32_t reader_pid_ = 1;
Austin Schuhe5f064d2016-03-05 17:43:51 -0800195 double battery_voltage_ = 12.4;
Philipp Schraderf75a8bf2015-02-02 05:30:16 +0000196
Austin Schuh6a6f90c2016-11-25 21:36:42 -0800197 ::aos::monotonic_clock::time_point last_ds_time_ =
Austin Schuh9fe68f72019-08-10 19:32:03 -0700198 ::aos::monotonic_clock::min_time;
Brian Silverman65e49702014-04-30 17:36:40 -0700199
Austin Schuh9fe68f72019-08-10 19:32:03 -0700200 bool enabled_ = false;
Campbell Crowley152c7cf2016-02-14 21:20:50 -0800201
Austin Schuh9fe68f72019-08-10 19:32:03 -0700202 ::std::unique_ptr<::aos::EventLoop> robot_status_event_loop_;
Austin Schuhdf6cbb12019-02-02 13:46:52 -0800203
204 ::aos::Sender<::aos::RobotState> robot_state_sender_;
205 ::aos::Sender<::aos::JoystickState> joystick_state_sender_;
Austin Schuh9fe68f72019-08-10 19:32:03 -0700206
207 ::aos::PhasedLoopHandler *send_robot_state_phased_loop_ = nullptr;
208 ::aos::TimerHandler *send_joystick_state_timer_ = nullptr;
Brian Silverman65e49702014-04-30 17:36:40 -0700209};
210
Austin Schuh2001aa42018-10-29 22:57:02 -0700211typedef ControlLoopTestTemplated<::testing::Test> ControlLoopTest;
212
213template <typename TestBaseClass>
Austin Schuh9fe68f72019-08-10 19:32:03 -0700214constexpr ::std::chrono::microseconds
215 ControlLoopTestTemplated<TestBaseClass>::kTimeTick;
Austin Schuh2001aa42018-10-29 22:57:02 -0700216
217template <typename TestBaseClass>
Tyler Chatow67ddb032020-01-12 14:30:04 -0800218constexpr ::std::chrono::milliseconds
219 ControlLoopTestTemplated<TestBaseClass>::kDSPacketTime;
Austin Schuh2001aa42018-10-29 22:57:02 -0700220
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800221} // namespace frc971::testing
Brian Silverman65e49702014-04-30 17:36:40 -0700222
John Park33858a32018-09-28 23:05:48 -0700223#endif // AOS_CONTROLS_CONTROL_LOOP_TEST_H_