blob: b062ceb7eaa11f0b36c692e80fe7ff38b34a390b [file] [log] [blame]
James Kuszmaul7077d342021-06-09 20:23:58 -07001#include "frc971/input/drivetrain_input.h"
Sabina Davis92d2efa2017-11-04 22:35:25 -07002
Sabina Davis92d2efa2017-11-04 22:35:25 -07003#include <cmath>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07004#include <cstdio>
5#include <cstring>
Sabina Davis92d2efa2017-11-04 22:35:25 -07006
John Park33858a32018-09-28 23:05:48 -07007#include "aos/commonmath.h"
John Park33858a32018-09-28 23:05:48 -07008#include "aos/logging/logging.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -07009#include "frc971/control_loops/control_loops_generated.h"
10#include "frc971/control_loops/drivetrain/drivetrain_goal_generated.h"
11#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
James Kuszmaul7077d342021-06-09 20:23:58 -070012#include "frc971/input/driver_station_data.h"
Sabina Davis92d2efa2017-11-04 22:35:25 -070013
James Kuszmaul7077d342021-06-09 20:23:58 -070014using ::frc971::input::driver_station::ButtonLocation;
15using ::frc971::input::driver_station::ControlBit;
16using ::frc971::input::driver_station::JoystickAxis;
17using ::frc971::input::driver_station::POVLocation;
Sabina Davis92d2efa2017-11-04 22:35:25 -070018
Alex Perrycb7da4b2019-08-28 19:35:56 -070019namespace drivetrain = frc971::control_loops::drivetrain;
20
James Kuszmaul7077d342021-06-09 20:23:58 -070021namespace frc971 {
Sabina Davis92d2efa2017-11-04 22:35:25 -070022namespace input {
23
Sabina Davis82b19182017-11-10 09:30:25 -080024const ButtonLocation kShiftHigh(2, 3), kShiftHigh2(2, 2), kShiftLow(2, 1);
25
Sabina Davis92d2efa2017-11-04 22:35:25 -070026void DrivetrainInputReader::HandleDrivetrain(
James Kuszmaul7077d342021-06-09 20:23:58 -070027 const ::frc971::input::driver_station::Data &data) {
Sabina Davis92d2efa2017-11-04 22:35:25 -070028 const auto wheel_and_throttle = GetWheelAndThrottle(data);
29 const double wheel = wheel_and_throttle.wheel;
Austin Schuh2b1fce02018-03-02 20:05:20 -080030 const double wheel_velocity = wheel_and_throttle.wheel_velocity;
31 const double wheel_torque = wheel_and_throttle.wheel_torque;
Sabina Davis92d2efa2017-11-04 22:35:25 -070032 const double throttle = wheel_and_throttle.throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -080033 const double throttle_velocity = wheel_and_throttle.throttle_velocity;
34 const double throttle_torque = wheel_and_throttle.throttle_torque;
Sabina Davis82b19182017-11-10 09:30:25 -080035 const bool high_gear = wheel_and_throttle.high_gear;
Sabina Davis92d2efa2017-11-04 22:35:25 -070036
Austin Schuhbd0a40f2019-06-30 14:56:31 -070037 drivetrain_status_fetcher_.Fetch();
38 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070039 robot_velocity_ = drivetrain_status_fetcher_->robot_speed();
Sabina Davis92d2efa2017-11-04 22:35:25 -070040 }
41
Austin Schuha250b2d2019-05-27 16:14:02 -070042 // If we have a vision align function, and it is in control, don't run the
43 // normal driving code.
44 if (vision_align_fn_) {
45 if (vision_align_fn_(data)) {
46 return;
47 }
48 }
49
James Kuszmaul8bad2412019-03-10 10:47:56 -070050 bool is_control_loop_driving = false;
51 bool is_line_following = false;
52
53 if (data.IsPressed(turn1_)) {
54 switch (turn1_use_) {
55 case TurnButtonUse::kControlLoopDriving:
56 is_control_loop_driving = true;
57 break;
58 case TurnButtonUse::kLineFollow:
59 is_line_following = true;
60 break;
61 }
62 }
63
64 if (data.IsPressed(turn2_)) {
65 switch (turn2_use_) {
66 case TurnButtonUse::kControlLoopDriving:
67 is_control_loop_driving = true;
68 break;
69 case TurnButtonUse::kLineFollow:
70 is_line_following = true;
71 break;
72 }
73 }
74
Austin Schuhbd0a40f2019-06-30 14:56:31 -070075 if (drivetrain_status_fetcher_.get()) {
Austin Schuh48d3a962019-03-17 18:12:32 -070076 if (is_control_loop_driving && !last_is_control_loop_driving_) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070077 left_goal_ = drivetrain_status_fetcher_->estimated_left_position() +
Austin Schuhf9202e82019-03-22 21:55:11 -070078 wheel * wheel_multiplier_;
Alex Perrycb7da4b2019-08-28 19:35:56 -070079 right_goal_ = drivetrain_status_fetcher_->estimated_right_position() -
Austin Schuhf9202e82019-03-22 21:55:11 -070080 wheel * wheel_multiplier_;
Sabina Davis92d2efa2017-11-04 22:35:25 -070081 }
82 }
Austin Schuh48d3a962019-03-17 18:12:32 -070083
Sabina Davis92d2efa2017-11-04 22:35:25 -070084 const double current_left_goal =
85 left_goal_ - wheel * wheel_multiplier_ + throttle * 0.3;
86 const double current_right_goal =
87 right_goal_ + wheel * wheel_multiplier_ + throttle * 0.3;
Alex Perrycb7da4b2019-08-28 19:35:56 -070088 auto builder = drivetrain_goal_sender_.MakeBuilder();
Sabina Davis92d2efa2017-11-04 22:35:25 -070089
Alex Perrycb7da4b2019-08-28 19:35:56 -070090 frc971::ProfileParameters::Builder linear_builder =
91 builder.MakeBuilder<frc971::ProfileParameters>();
Sabina Davis92d2efa2017-11-04 22:35:25 -070092
Alex Perrycb7da4b2019-08-28 19:35:56 -070093 linear_builder.add_max_velocity(3.0);
94 linear_builder.add_max_acceleration(20.0);
95
96 flatbuffers::Offset<frc971::ProfileParameters> linear_offset =
97 linear_builder.Finish();
98
99 auto goal_builder = builder.MakeBuilder<drivetrain::Goal>();
100 goal_builder.add_wheel(wheel);
101 goal_builder.add_wheel_velocity(wheel_velocity);
102 goal_builder.add_wheel_torque(wheel_torque);
103 goal_builder.add_throttle(throttle);
104 goal_builder.add_throttle_velocity(throttle_velocity);
105 goal_builder.add_throttle_torque(throttle_torque);
106 goal_builder.add_highgear(high_gear);
107 goal_builder.add_quickturn(data.IsPressed(quick_turn_));
108 goal_builder.add_controller_type(
James Kuszmaul7077d342021-06-09 20:23:58 -0700109 is_line_following ? drivetrain::ControllerType::LINE_FOLLOWER
110 : (is_control_loop_driving
111 ? drivetrain::ControllerType::MOTION_PROFILE
112 : drivetrain::ControllerType::POLYDRIVE));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700113 goal_builder.add_left_goal(current_left_goal);
114 goal_builder.add_right_goal(current_right_goal);
115 goal_builder.add_linear(linear_offset);
116
117 if (!builder.Send(goal_builder.Finish())) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700118 AOS_LOG(WARNING, "sending stick values failed\n");
Sabina Davis92d2efa2017-11-04 22:35:25 -0700119 }
Austin Schuh48d3a962019-03-17 18:12:32 -0700120
121 last_is_control_loop_driving_ = is_control_loop_driving;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700122}
123
124DrivetrainInputReader::WheelAndThrottle
125SteeringWheelDrivetrainInputReader::GetWheelAndThrottle(
James Kuszmaul7077d342021-06-09 20:23:58 -0700126 const ::frc971::input::driver_station::Data &data) {
Austin Schuh2b1fce02018-03-02 20:05:20 -0800127 const double wheel = -data.GetAxis(wheel_);
128 const double throttle = -data.GetAxis(throttle_);
Sabina Davis82b19182017-11-10 09:30:25 -0800129
130 if (!data.GetControlBit(ControlBit::kEnabled)) {
131 high_gear_ = default_high_gear_;
132 }
133
134 if (data.PosEdge(kShiftLow)) {
135 high_gear_ = false;
136 }
137
138 if (data.PosEdge(kShiftHigh) || data.PosEdge(kShiftHigh2)) {
139 high_gear_ = true;
140 }
141
Austin Schuh2b1fce02018-03-02 20:05:20 -0800142 return DrivetrainInputReader::WheelAndThrottle{
143 wheel, 0.0, 0.0, throttle, 0.0, 0.0, high_gear_};
144}
145
James Kuszmaul7077d342021-06-09 20:23:58 -0700146double UnwrappedAxis(const ::frc971::input::driver_station::Data &data,
Austin Schuh2b1fce02018-03-02 20:05:20 -0800147 const JoystickAxis &high_bits,
148 const JoystickAxis &low_bits) {
149 const float high_bits_data = data.GetAxis(high_bits);
150 const float low_bits_data = data.GetAxis(low_bits);
151 const int16_t high_bits_data_int =
152 (high_bits_data < 0.0f ? high_bits_data * 128.0f
153 : high_bits_data * 127.0f);
154 const int16_t low_bits_data_int =
155 (low_bits_data < 0.0f ? low_bits_data * 128.0f : low_bits_data * 127.0f);
156
157 const uint16_t high_bits_data_uint =
158 ((static_cast<uint16_t>(high_bits_data_int) & 0xff) + 0x80) & 0xff;
159 const uint16_t low_bits_data_uint =
160 ((static_cast<uint16_t>(low_bits_data_int) & 0xff) + 0x80) & 0xff;
161
162 const uint16_t data_uint = (high_bits_data_uint << 8) | low_bits_data_uint;
163
164 const int32_t data_int = static_cast<int32_t>(data_uint) - 0x8000;
165
166 if (data_int < 0) {
167 return static_cast<double>(data_int) / static_cast<double>(0x8000);
168 } else {
169 return static_cast<double>(data_int) / static_cast<double>(0x7fff);
170 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700171}
172
173DrivetrainInputReader::WheelAndThrottle
174PistolDrivetrainInputReader::GetWheelAndThrottle(
James Kuszmaul7077d342021-06-09 20:23:58 -0700175 const ::frc971::input::driver_station::Data &data) {
176 const double wheel = -UnwrappedAxis(data, wheel_, wheel_low_);
Austin Schuh2b1fce02018-03-02 20:05:20 -0800177 const double wheel_velocity =
178 -UnwrappedAxis(data, wheel_velocity_high_, wheel_velocity_low_) * 50.0;
179 const double wheel_torque =
180 -UnwrappedAxis(data, wheel_torque_high_, wheel_torque_low_) / 2.0;
181
James Kuszmaul7077d342021-06-09 20:23:58 -0700182 double throttle = UnwrappedAxis(data, throttle_, throttle_low_);
Austin Schuh2b1fce02018-03-02 20:05:20 -0800183 const double throttle_velocity =
James Kuszmaul7077d342021-06-09 20:23:58 -0700184 UnwrappedAxis(data, throttle_velocity_high_, throttle_velocity_low_) *
185 50.0;
Austin Schuh2b1fce02018-03-02 20:05:20 -0800186 const double throttle_torque =
187 UnwrappedAxis(data, throttle_torque_high_, throttle_torque_low_) / 2.0;
188
Austin Schuh876b4f02018-03-10 19:16:59 -0800189 // TODO(austin): Deal with haptics here.
190 if (throttle < 0) {
191 throttle = ::std::max(-1.0, throttle / 0.7);
192 }
193
James Kuszmaulc4eb1b22019-04-13 15:48:34 -0700194 if (data.IsPressed(slow_down_)) {
195 throttle *= 0.5;
196 }
197
Austin Schuh2b1fce02018-03-02 20:05:20 -0800198 if (!data.GetControlBit(ControlBit::kEnabled)) {
199 high_gear_ = default_high_gear_;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700200 }
201
Austin Schuh2b1fce02018-03-02 20:05:20 -0800202 if (data.PosEdge(shift_low_)) {
203 high_gear_ = false;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700204 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700205
Austin Schuh2b1fce02018-03-02 20:05:20 -0800206 if (data.PosEdge(shift_high_)) {
207 high_gear_ = true;
208 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700209
Austin Schuh2b1fce02018-03-02 20:05:20 -0800210 return DrivetrainInputReader::WheelAndThrottle{
James Kuszmaul7077d342021-06-09 20:23:58 -0700211 wheel, wheel_velocity, wheel_torque,
212 throttle, throttle_velocity, throttle_torque,
Austin Schuh2b1fce02018-03-02 20:05:20 -0800213 high_gear_};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700214}
215
216DrivetrainInputReader::WheelAndThrottle
217XboxDrivetrainInputReader::GetWheelAndThrottle(
James Kuszmaul7077d342021-06-09 20:23:58 -0700218 const ::frc971::input::driver_station::Data &data) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700219 // xbox
220 constexpr double kWheelDeadband = 0.05;
221 constexpr double kThrottleDeadband = 0.05;
222 const double wheel =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800223 aos::Deadband(-data.GetAxis(wheel_), kWheelDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700224
225 const double unmodified_throttle =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800226 aos::Deadband(-data.GetAxis(throttle_), kThrottleDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700227
228 // Apply a sin function that's scaled to make it feel better.
229 constexpr double throttle_range = M_PI_2 * 0.9;
230
231 double throttle = ::std::sin(throttle_range * unmodified_throttle) /
232 ::std::sin(throttle_range);
233 throttle = ::std::sin(throttle_range * throttle) / ::std::sin(throttle_range);
234 throttle = 2.0 * unmodified_throttle - throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -0800235 return DrivetrainInputReader::WheelAndThrottle{wheel, 0.0, 0.0, throttle,
236 0.0, 0.0, true};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700237}
238
239std::unique_ptr<SteeringWheelDrivetrainInputReader>
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700240SteeringWheelDrivetrainInputReader::Make(::aos::EventLoop *event_loop,
241 bool default_high_gear) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700242 const JoystickAxis kSteeringWheel(1, 1), kDriveThrottle(2, 2);
243 const ButtonLocation kQuickTurn(1, 5);
244 const ButtonLocation kTurn1(1, 7);
245 const ButtonLocation kTurn2(1, 11);
246 std::unique_ptr<SteeringWheelDrivetrainInputReader> result(
James Kuszmaul8bad2412019-03-10 10:47:56 -0700247 new SteeringWheelDrivetrainInputReader(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700248 event_loop, kSteeringWheel, kDriveThrottle, kQuickTurn, kTurn1,
James Kuszmaul8bad2412019-03-10 10:47:56 -0700249 TurnButtonUse::kControlLoopDriving, kTurn2,
250 TurnButtonUse::kControlLoopDriving));
Sabina Davis82b19182017-11-10 09:30:25 -0800251 result.get()->set_default_high_gear(default_high_gear);
252
Sabina Davis92d2efa2017-11-04 22:35:25 -0700253 return result;
254}
255
Austin Schuh2b1fce02018-03-02 20:05:20 -0800256std::unique_ptr<PistolDrivetrainInputReader> PistolDrivetrainInputReader::Make(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700257 ::aos::EventLoop *event_loop, bool default_high_gear,
258 TopButtonUse top_button_use) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700259 // Pistol Grip controller
Austin Schuh2b1fce02018-03-02 20:05:20 -0800260 const JoystickAxis kTriggerHigh(1, 1), kTriggerLow(1, 4),
261 kTriggerVelocityHigh(1, 2), kTriggerVelocityLow(1, 5),
262 kTriggerTorqueHigh(1, 3), kTriggerTorqueLow(1, 6);
263
264 const JoystickAxis kWheelHigh(2, 1), kWheelLow(2, 4),
265 kWheelVelocityHigh(2, 2), kWheelVelocityLow(2, 5), kWheelTorqueHigh(2, 3),
266 kWheelTorqueLow(2, 6);
267
Austin Schuhe8a54c02018-03-05 00:25:58 -0800268 const ButtonLocation kQuickTurn(1, 3);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700269
James Kuszmaul8bad2412019-03-10 10:47:56 -0700270 const ButtonLocation TopButton(1, 1);
271 const ButtonLocation SecondButton(1, 2);
James Kuszmaulc4eb1b22019-04-13 15:48:34 -0700272 const ButtonLocation BottomButton(1, 4);
James Kuszmaul8bad2412019-03-10 10:47:56 -0700273 // Non-existant button for nops.
274 const ButtonLocation DummyButton(1, 10);
275
276 // TODO(james): Make a copy assignment operator for ButtonLocation so we don't
277 // have to shoehorn in these ternary operators.
Austin Schuh48d3a962019-03-17 18:12:32 -0700278 const ButtonLocation kTurn1 = (top_button_use == TopButtonUse::kLineFollow)
279 ? SecondButton
280 : DummyButton;
281 // Turn2 does closed loop driving.
282 const ButtonLocation kTurn2 =
James Kuszmaul8bad2412019-03-10 10:47:56 -0700283 (top_button_use == TopButtonUse::kLineFollow) ? TopButton : DummyButton;
Austin Schuh48d3a962019-03-17 18:12:32 -0700284
James Kuszmaul8bad2412019-03-10 10:47:56 -0700285 const ButtonLocation kShiftHigh =
286 (top_button_use == TopButtonUse::kShift) ? TopButton : DummyButton;
287 const ButtonLocation kShiftLow =
288 (top_button_use == TopButtonUse::kShift) ? SecondButton : DummyButton;
289
Sabina Davis92d2efa2017-11-04 22:35:25 -0700290 std::unique_ptr<PistolDrivetrainInputReader> result(
Austin Schuh2b1fce02018-03-02 20:05:20 -0800291 new PistolDrivetrainInputReader(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700292 event_loop, kWheelHigh, kWheelLow, kTriggerVelocityHigh,
293 kTriggerVelocityLow, kTriggerTorqueHigh, kTriggerTorqueLow,
294 kTriggerHigh, kTriggerLow, kWheelVelocityHigh, kWheelVelocityLow,
295 kWheelTorqueHigh, kWheelTorqueLow, kQuickTurn, kShiftHigh, kShiftLow,
296 kTurn1, kTurn2, BottomButton));
Austin Schuh2b1fce02018-03-02 20:05:20 -0800297
298 result->set_default_high_gear(default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700299 return result;
300}
301
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700302std::unique_ptr<XboxDrivetrainInputReader> XboxDrivetrainInputReader::Make(
303 ::aos::EventLoop *event_loop) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700304 // xbox
305 const JoystickAxis kSteeringWheel(1, 5), kDriveThrottle(1, 2);
306 const ButtonLocation kQuickTurn(1, 5);
307
308 // Nop
309 const ButtonLocation kTurn1(1, 1);
310 const ButtonLocation kTurn2(1, 2);
311
312 std::unique_ptr<XboxDrivetrainInputReader> result(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700313 new XboxDrivetrainInputReader(event_loop, kSteeringWheel, kDriveThrottle,
314 kQuickTurn, kTurn1,
315 TurnButtonUse::kControlLoopDriving, kTurn2,
James Kuszmaul8bad2412019-03-10 10:47:56 -0700316 TurnButtonUse::kControlLoopDriving));
Sabina Davis92d2efa2017-11-04 22:35:25 -0700317 return result;
318}
319::std::unique_ptr<DrivetrainInputReader> DrivetrainInputReader::Make(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700320 ::aos::EventLoop *event_loop, InputType type,
Alex Perrycb7da4b2019-08-28 19:35:56 -0700321 const drivetrain::DrivetrainConfig<double> &dt_config) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700322 std::unique_ptr<DrivetrainInputReader> drivetrain_input_reader;
323
324 using InputType = DrivetrainInputReader::InputType;
Sabina Davis82b19182017-11-10 09:30:25 -0800325
Sabina Davis92d2efa2017-11-04 22:35:25 -0700326 switch (type) {
327 case InputType::kSteeringWheel:
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700328 drivetrain_input_reader = SteeringWheelDrivetrainInputReader::Make(
329 event_loop, dt_config.default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700330 break;
331 case InputType::kPistol:
James Kuszmaul8bad2412019-03-10 10:47:56 -0700332 drivetrain_input_reader = PistolDrivetrainInputReader::Make(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700333 event_loop, dt_config.default_high_gear,
James Kuszmaul8bad2412019-03-10 10:47:56 -0700334 dt_config.pistol_grip_shift_enables_line_follow
335 ? PistolDrivetrainInputReader::TopButtonUse::kLineFollow
336 : PistolDrivetrainInputReader::TopButtonUse::kShift);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700337 break;
338 case InputType::kXbox:
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700339 drivetrain_input_reader = XboxDrivetrainInputReader::Make(event_loop);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700340 break;
341 }
342 return drivetrain_input_reader;
343}
344
345} // namespace input
James Kuszmaul7077d342021-06-09 20:23:58 -0700346} // namespace frc971