blob: a820215aeeec65354660ec7351126f8314c8293c [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
Alex Perrycb7da4b2019-08-28 19:35:56 -07007#include "aos/events/simulated_event_loop.h"
8#include "aos/flatbuffers.h"
9#include "aos/json_to_flatbuffer.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070010#include "aos/testing/test_logging.h"
John Park33858a32018-09-28 23:05:48 -070011#include "aos/time/time.h"
James Kuszmaul7077d342021-06-09 20:23:58 -070012#include "frc971/input/joystick_state_generated.h"
13#include "frc971/input/robot_state_generated.h"
milind1f1dca32021-07-03 13:50:07 -070014#include "glog/logging.h"
Tyler Chatow67ddb032020-01-12 14:30:04 -080015#include "gtest/gtest.h"
Brian Silverman65e49702014-04-30 17:36:40 -070016
James Kuszmaul61750662021-06-21 21:32:33 -070017namespace frc971 {
Brian Silverman65e49702014-04-30 17:36:40 -070018namespace testing {
19
20// Handles setting up the environment that all control loops need to actually
21// run.
22// This includes sending the queue messages and Clear()ing the queues when
23// appropriate.
24// It also includes dealing with ::aos::time.
Austin Schuh2001aa42018-10-29 22:57:02 -070025template <typename TestBaseClass>
26class ControlLoopTestTemplated : public TestBaseClass {
Brian Silverman65e49702014-04-30 17:36:40 -070027 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070028 ControlLoopTestTemplated(
James Kuszmaul61750662021-06-21 21:32:33 -070029 aos::FlatbufferDetachedBuffer<aos::Configuration> configuration,
Alex Perrycb7da4b2019-08-28 19:35:56 -070030 ::std::chrono::nanoseconds dt = kTimeTick)
31 : configuration_(std::move(configuration)),
32 event_loop_factory_(&configuration_.message()),
33 dt_(dt),
Austin Schuh08e96eb2020-02-25 23:36:30 -080034 robot_status_event_loop_(MakeEventLoop(
35 "robot_status",
James Kuszmaul61750662021-06-21 21:32:33 -070036 aos::configuration::MultiNode(event_loop_factory_.configuration())
37 ? aos::configuration::GetNode(
38 event_loop_factory_.configuration(), "roborio")
Austin Schuh08e96eb2020-02-25 23:36:30 -080039 : nullptr)) {
James Kuszmaul61750662021-06-21 21:32:33 -070040 aos::testing::EnableTestLogging();
Austin Schuhdf6cbb12019-02-02 13:46:52 -080041 robot_state_sender_ =
Alex Perrycb7da4b2019-08-28 19:35:56 -070042 robot_status_event_loop_->MakeSender<::aos::RobotState>("/aos");
Austin Schuhdf6cbb12019-02-02 13:46:52 -080043 joystick_state_sender_ =
Alex Perrycb7da4b2019-08-28 19:35:56 -070044 robot_status_event_loop_->MakeSender<::aos::JoystickState>("/aos");
Austin Schuh2001aa42018-10-29 22:57:02 -070045
Austin Schuh9fe68f72019-08-10 19:32:03 -070046 // Schedule the robot status send 1 nanosecond before the loop runs.
47 send_robot_state_phased_loop_ = robot_status_event_loop_->AddPhasedLoop(
48 [this](int) { SendRobotState(); }, dt_,
49 dt - ::std::chrono::nanoseconds(1));
Austin Schuh2001aa42018-10-29 22:57:02 -070050
Austin Schuh9fe68f72019-08-10 19:32:03 -070051 send_joystick_state_timer_ =
52 robot_status_event_loop_->AddTimer([this]() { SendJoystickState(); });
53
54 robot_status_event_loop_->OnRun([this]() {
55 send_joystick_state_timer_->Setup(
56 robot_status_event_loop_->monotonic_now(), dt_);
57 });
Austin Schuh2001aa42018-10-29 22:57:02 -070058 }
Austin Schuh9fe68f72019-08-10 19:32:03 -070059 virtual ~ControlLoopTestTemplated() {}
Brian Silverman65e49702014-04-30 17:36:40 -070060
Philipp Schraderf75a8bf2015-02-02 05:30:16 +000061 void set_team_id(uint16_t team_id) { team_id_ = team_id; }
62 uint16_t team_id() const { return team_id_; }
63
Austin Schuh9fe68f72019-08-10 19:32:03 -070064 // Sets the enabled/disabled bit and (potentially) rebroadcasts the robot
65 // state messages.
66 void SetEnabled(bool enabled) {
67 if (enabled_ != enabled) {
68 enabled_ = enabled;
69 SendJoystickState();
70 SendRobotState();
71 send_joystick_state_timer_->Setup(
72 robot_status_event_loop_->monotonic_now(), dt_);
Austin Schuh2001aa42018-10-29 22:57:02 -070073 }
Brian Silvermane6f64ab2015-02-05 17:03:56 -050074 }
Brian Silverman65e49702014-04-30 17:36:40 -070075
Brian Silverman57cad222015-02-14 20:46:41 -050076 // Simulate a reset of the process reading sensors, which tells loops that all
77 // index counts etc will be reset.
Tyler Chatow67ddb032020-01-12 14:30:04 -080078 void SimulateSensorReset() { ++reader_pid_; }
Brian Silverman57cad222015-02-14 20:46:41 -050079
Austin Schuhe5f064d2016-03-05 17:43:51 -080080 // Sets the battery voltage in robot_state.
81 void set_battery_voltage(double battery_voltage) {
82 battery_voltage_ = battery_voltage;
83 }
84
Austin Schuh08e96eb2020-02-25 23:36:30 -080085 ::std::unique_ptr<::aos::EventLoop> MakeEventLoop(
James Kuszmaul61750662021-06-21 21:32:33 -070086 std::string_view name, const aos::Node *node = nullptr) {
Austin Schuh08e96eb2020-02-25 23:36:30 -080087 return event_loop_factory_.MakeEventLoop(name, node);
Austin Schuh9fe68f72019-08-10 19:32:03 -070088 }
89
Austin Schuh7d87b672019-12-01 20:23:49 -080090 void set_send_delay(std::chrono::nanoseconds send_delay) {
91 event_loop_factory_.set_send_delay(send_delay);
92 }
93
James Kuszmaul61750662021-06-21 21:32:33 -070094 void RunFor(aos::monotonic_clock::duration duration) {
Austin Schuh9fe68f72019-08-10 19:32:03 -070095 event_loop_factory_.RunFor(duration);
96 }
97
98 ::aos::monotonic_clock::time_point monotonic_now() {
Austin Schuha5e14192020-01-06 18:02:41 -080099 return robot_status_event_loop_->monotonic_now();
Austin Schuh9fe68f72019-08-10 19:32:03 -0700100 }
101
102 ::std::chrono::nanoseconds dt() const { return dt_; }
103
James Kuszmaul61750662021-06-21 21:32:33 -0700104 const aos::Configuration *configuration() const {
Austin Schuh08e96eb2020-02-25 23:36:30 -0800105 return &configuration_.message();
106 }
107
James Kuszmaul61750662021-06-21 21:32:33 -0700108 aos::SimulatedEventLoopFactory *event_loop_factory() {
James Kuszmaul958b21e2020-02-26 21:51:40 -0800109 return &event_loop_factory_;
110 }
111
Brian Silverman65e49702014-04-30 17:36:40 -0700112 private:
Austin Schuh9fe68f72019-08-10 19:32:03 -0700113 // Sends out all of the required queue messages.
114 void SendJoystickState() {
115 if (monotonic_now() >= kDSPacketTime + last_ds_time_ ||
116 last_enabled_ != enabled_) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700117 auto new_state = joystick_state_sender_.MakeBuilder();
118 ::aos::JoystickState::Builder builder =
119 new_state.template MakeBuilder<::aos::JoystickState>();
Austin Schuh9fe68f72019-08-10 19:32:03 -0700120
Alex Perrycb7da4b2019-08-28 19:35:56 -0700121 builder.add_fake(true);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700122
Alex Perrycb7da4b2019-08-28 19:35:56 -0700123 builder.add_enabled(enabled_);
124 builder.add_autonomous(false);
125 builder.add_team_id(team_id_);
126
milind1f1dca32021-07-03 13:50:07 -0700127 CHECK_EQ(new_state.Send(builder.Finish()),
128 aos::RawSender::Error::kOk);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700129
130 last_ds_time_ = monotonic_now();
131 last_enabled_ = enabled_;
132 }
133 }
134
135 bool last_enabled_ = false;
136
137 void SendRobotState() {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700138 auto new_state = robot_state_sender_.MakeBuilder();
Austin Schuh9fe68f72019-08-10 19:32:03 -0700139
Alex Perrycb7da4b2019-08-28 19:35:56 -0700140 ::aos::RobotState::Builder builder =
141 new_state.template MakeBuilder<::aos::RobotState>();
Austin Schuh9fe68f72019-08-10 19:32:03 -0700142
Alex Perrycb7da4b2019-08-28 19:35:56 -0700143 builder.add_reader_pid(reader_pid_);
144 builder.add_outputs_enabled(enabled_);
145 builder.add_browned_out(false);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700146
Alex Perrycb7da4b2019-08-28 19:35:56 -0700147 builder.add_is_3v3_active(true);
148 builder.add_is_5v_active(true);
149 builder.add_voltage_3v3(3.3);
150 builder.add_voltage_5v(5.0);
Austin Schuh9fe68f72019-08-10 19:32:03 -0700151
Alex Perrycb7da4b2019-08-28 19:35:56 -0700152 builder.add_voltage_roborio_in(battery_voltage_);
153 builder.add_voltage_battery(battery_voltage_);
154
milind1f1dca32021-07-03 13:50:07 -0700155 new_state.CheckOk(new_state.Send(builder.Finish()));
Austin Schuh9fe68f72019-08-10 19:32:03 -0700156 }
157
158 static constexpr ::std::chrono::microseconds kTimeTick{5000};
Austin Schuh6a6f90c2016-11-25 21:36:42 -0800159 static constexpr ::std::chrono::milliseconds kDSPacketTime{20};
Brian Silvermane6f64ab2015-02-05 17:03:56 -0500160
James Kuszmaul61750662021-06-21 21:32:33 -0700161 aos::FlatbufferDetachedBuffer<aos::Configuration> configuration_;
Austin Schuh9fe68f72019-08-10 19:32:03 -0700162
James Kuszmaul61750662021-06-21 21:32:33 -0700163 aos::SimulatedEventLoopFactory event_loop_factory_;
Austin Schuh9fe68f72019-08-10 19:32:03 -0700164
Alex Perrycb7da4b2019-08-28 19:35:56 -0700165 const ::std::chrono::nanoseconds dt_;
166
Philipp Schraderf75a8bf2015-02-02 05:30:16 +0000167 uint16_t team_id_ = 971;
Brian Silverman57cad222015-02-14 20:46:41 -0500168 int32_t reader_pid_ = 1;
Austin Schuhe5f064d2016-03-05 17:43:51 -0800169 double battery_voltage_ = 12.4;
Philipp Schraderf75a8bf2015-02-02 05:30:16 +0000170
Austin Schuh6a6f90c2016-11-25 21:36:42 -0800171 ::aos::monotonic_clock::time_point last_ds_time_ =
Austin Schuh9fe68f72019-08-10 19:32:03 -0700172 ::aos::monotonic_clock::min_time;
Brian Silverman65e49702014-04-30 17:36:40 -0700173
Austin Schuh9fe68f72019-08-10 19:32:03 -0700174 bool enabled_ = false;
Campbell Crowley152c7cf2016-02-14 21:20:50 -0800175
Austin Schuh9fe68f72019-08-10 19:32:03 -0700176 ::std::unique_ptr<::aos::EventLoop> robot_status_event_loop_;
Austin Schuhdf6cbb12019-02-02 13:46:52 -0800177
178 ::aos::Sender<::aos::RobotState> robot_state_sender_;
179 ::aos::Sender<::aos::JoystickState> joystick_state_sender_;
Austin Schuh9fe68f72019-08-10 19:32:03 -0700180
181 ::aos::PhasedLoopHandler *send_robot_state_phased_loop_ = nullptr;
182 ::aos::TimerHandler *send_joystick_state_timer_ = nullptr;
Brian Silverman65e49702014-04-30 17:36:40 -0700183};
184
Austin Schuh2001aa42018-10-29 22:57:02 -0700185typedef ControlLoopTestTemplated<::testing::Test> ControlLoopTest;
186
187template <typename TestBaseClass>
Austin Schuh9fe68f72019-08-10 19:32:03 -0700188constexpr ::std::chrono::microseconds
189 ControlLoopTestTemplated<TestBaseClass>::kTimeTick;
Austin Schuh2001aa42018-10-29 22:57:02 -0700190
191template <typename TestBaseClass>
Tyler Chatow67ddb032020-01-12 14:30:04 -0800192constexpr ::std::chrono::milliseconds
193 ControlLoopTestTemplated<TestBaseClass>::kDSPacketTime;
Austin Schuh2001aa42018-10-29 22:57:02 -0700194
Brian Silverman65e49702014-04-30 17:36:40 -0700195} // namespace testing
James Kuszmaul61750662021-06-21 21:32:33 -0700196} // namespace frc971
Brian Silverman65e49702014-04-30 17:36:40 -0700197
John Park33858a32018-09-28 23:05:48 -0700198#endif // AOS_CONTROLS_CONTROL_LOOP_TEST_H_