blob: 687c8bb491e2d2509873f4a0a3797145ee245110 [file] [log] [blame]
Sabina Davis92d2efa2017-11-04 22:35:25 -07001#include "aos/input/drivetrain_input.h"
2
3#include <math.h>
4#include <stdio.h>
5#include <string.h>
6#include <cmath>
7
John Park33858a32018-09-28 23:05:48 -07008#include "aos/commonmath.h"
9#include "aos/input/driver_station_data.h"
10#include "aos/logging/logging.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070011#include "frc971/control_loops/control_loops_generated.h"
12#include "frc971/control_loops/drivetrain/drivetrain_goal_generated.h"
13#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
Sabina Davis92d2efa2017-11-04 22:35:25 -070014
Sabina Davis92d2efa2017-11-04 22:35:25 -070015using ::aos::input::driver_station::ButtonLocation;
16using ::aos::input::driver_station::ControlBit;
17using ::aos::input::driver_station::JoystickAxis;
18using ::aos::input::driver_station::POVLocation;
19
Alex Perrycb7da4b2019-08-28 19:35:56 -070020namespace drivetrain = frc971::control_loops::drivetrain;
21
Sabina Davis92d2efa2017-11-04 22:35:25 -070022namespace aos {
23namespace input {
24
Sabina Davis82b19182017-11-10 09:30:25 -080025const ButtonLocation kShiftHigh(2, 3), kShiftHigh2(2, 2), kShiftLow(2, 1);
26
Sabina Davis92d2efa2017-11-04 22:35:25 -070027void DrivetrainInputReader::HandleDrivetrain(
28 const ::aos::input::driver_station::Data &data) {
Sabina Davis92d2efa2017-11-04 22:35:25 -070029 const auto wheel_and_throttle = GetWheelAndThrottle(data);
30 const double wheel = wheel_and_throttle.wheel;
Austin Schuh2b1fce02018-03-02 20:05:20 -080031 const double wheel_velocity = wheel_and_throttle.wheel_velocity;
32 const double wheel_torque = wheel_and_throttle.wheel_torque;
Sabina Davis92d2efa2017-11-04 22:35:25 -070033 const double throttle = wheel_and_throttle.throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -080034 const double throttle_velocity = wheel_and_throttle.throttle_velocity;
35 const double throttle_torque = wheel_and_throttle.throttle_torque;
Sabina Davis82b19182017-11-10 09:30:25 -080036 const bool high_gear = wheel_and_throttle.high_gear;
Sabina Davis92d2efa2017-11-04 22:35:25 -070037
Austin Schuhbd0a40f2019-06-30 14:56:31 -070038 drivetrain_status_fetcher_.Fetch();
39 if (drivetrain_status_fetcher_.get()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070040 robot_velocity_ = drivetrain_status_fetcher_->robot_speed();
Sabina Davis92d2efa2017-11-04 22:35:25 -070041 }
42
Austin Schuha250b2d2019-05-27 16:14:02 -070043 // If we have a vision align function, and it is in control, don't run the
44 // normal driving code.
45 if (vision_align_fn_) {
46 if (vision_align_fn_(data)) {
47 return;
48 }
49 }
50
James Kuszmaul8bad2412019-03-10 10:47:56 -070051 bool is_control_loop_driving = false;
52 bool is_line_following = false;
53
54 if (data.IsPressed(turn1_)) {
55 switch (turn1_use_) {
56 case TurnButtonUse::kControlLoopDriving:
57 is_control_loop_driving = true;
58 break;
59 case TurnButtonUse::kLineFollow:
60 is_line_following = true;
61 break;
62 }
63 }
64
65 if (data.IsPressed(turn2_)) {
66 switch (turn2_use_) {
67 case TurnButtonUse::kControlLoopDriving:
68 is_control_loop_driving = true;
69 break;
70 case TurnButtonUse::kLineFollow:
71 is_line_following = true;
72 break;
73 }
74 }
75
Austin Schuhbd0a40f2019-06-30 14:56:31 -070076 if (drivetrain_status_fetcher_.get()) {
Austin Schuh48d3a962019-03-17 18:12:32 -070077 if (is_control_loop_driving && !last_is_control_loop_driving_) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070078 left_goal_ = drivetrain_status_fetcher_->estimated_left_position() +
Austin Schuhf9202e82019-03-22 21:55:11 -070079 wheel * wheel_multiplier_;
Alex Perrycb7da4b2019-08-28 19:35:56 -070080 right_goal_ = drivetrain_status_fetcher_->estimated_right_position() -
Austin Schuhf9202e82019-03-22 21:55:11 -070081 wheel * wheel_multiplier_;
Sabina Davis92d2efa2017-11-04 22:35:25 -070082 }
83 }
Austin Schuh48d3a962019-03-17 18:12:32 -070084
Sabina Davis92d2efa2017-11-04 22:35:25 -070085 const double current_left_goal =
86 left_goal_ - wheel * wheel_multiplier_ + throttle * 0.3;
87 const double current_right_goal =
88 right_goal_ + wheel * wheel_multiplier_ + throttle * 0.3;
Alex Perrycb7da4b2019-08-28 19:35:56 -070089 auto builder = drivetrain_goal_sender_.MakeBuilder();
Sabina Davis92d2efa2017-11-04 22:35:25 -070090
Alex Perrycb7da4b2019-08-28 19:35:56 -070091 frc971::ProfileParameters::Builder linear_builder =
92 builder.MakeBuilder<frc971::ProfileParameters>();
Sabina Davis92d2efa2017-11-04 22:35:25 -070093
Alex Perrycb7da4b2019-08-28 19:35:56 -070094 linear_builder.add_max_velocity(3.0);
95 linear_builder.add_max_acceleration(20.0);
96
97 flatbuffers::Offset<frc971::ProfileParameters> linear_offset =
98 linear_builder.Finish();
99
100 auto goal_builder = builder.MakeBuilder<drivetrain::Goal>();
101 goal_builder.add_wheel(wheel);
102 goal_builder.add_wheel_velocity(wheel_velocity);
103 goal_builder.add_wheel_torque(wheel_torque);
104 goal_builder.add_throttle(throttle);
105 goal_builder.add_throttle_velocity(throttle_velocity);
106 goal_builder.add_throttle_torque(throttle_torque);
107 goal_builder.add_highgear(high_gear);
108 goal_builder.add_quickturn(data.IsPressed(quick_turn_));
109 goal_builder.add_controller_type(
110 is_line_following
111 ? drivetrain::ControllerType_LINE_FOLLOWER
112 : (is_control_loop_driving ? drivetrain::ControllerType_MOTION_PROFILE
113 : drivetrain::ControllerType_POLYDRIVE));
114 goal_builder.add_left_goal(current_left_goal);
115 goal_builder.add_right_goal(current_right_goal);
116 goal_builder.add_linear(linear_offset);
117
118 if (!builder.Send(goal_builder.Finish())) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700119 AOS_LOG(WARNING, "sending stick values failed\n");
Sabina Davis92d2efa2017-11-04 22:35:25 -0700120 }
Austin Schuh48d3a962019-03-17 18:12:32 -0700121
122 last_is_control_loop_driving_ = is_control_loop_driving;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700123}
124
125DrivetrainInputReader::WheelAndThrottle
126SteeringWheelDrivetrainInputReader::GetWheelAndThrottle(
127 const ::aos::input::driver_station::Data &data) {
Austin Schuh2b1fce02018-03-02 20:05:20 -0800128 const double wheel = -data.GetAxis(wheel_);
129 const double throttle = -data.GetAxis(throttle_);
Sabina Davis82b19182017-11-10 09:30:25 -0800130
131 if (!data.GetControlBit(ControlBit::kEnabled)) {
132 high_gear_ = default_high_gear_;
133 }
134
135 if (data.PosEdge(kShiftLow)) {
136 high_gear_ = false;
137 }
138
139 if (data.PosEdge(kShiftHigh) || data.PosEdge(kShiftHigh2)) {
140 high_gear_ = true;
141 }
142
Austin Schuh2b1fce02018-03-02 20:05:20 -0800143 return DrivetrainInputReader::WheelAndThrottle{
144 wheel, 0.0, 0.0, throttle, 0.0, 0.0, high_gear_};
145}
146
147double UnwrappedAxis(const ::aos::input::driver_station::Data &data,
148 const JoystickAxis &high_bits,
149 const JoystickAxis &low_bits) {
150 const float high_bits_data = data.GetAxis(high_bits);
151 const float low_bits_data = data.GetAxis(low_bits);
152 const int16_t high_bits_data_int =
153 (high_bits_data < 0.0f ? high_bits_data * 128.0f
154 : high_bits_data * 127.0f);
155 const int16_t low_bits_data_int =
156 (low_bits_data < 0.0f ? low_bits_data * 128.0f : low_bits_data * 127.0f);
157
158 const uint16_t high_bits_data_uint =
159 ((static_cast<uint16_t>(high_bits_data_int) & 0xff) + 0x80) & 0xff;
160 const uint16_t low_bits_data_uint =
161 ((static_cast<uint16_t>(low_bits_data_int) & 0xff) + 0x80) & 0xff;
162
163 const uint16_t data_uint = (high_bits_data_uint << 8) | low_bits_data_uint;
164
165 const int32_t data_int = static_cast<int32_t>(data_uint) - 0x8000;
166
167 if (data_int < 0) {
168 return static_cast<double>(data_int) / static_cast<double>(0x8000);
169 } else {
170 return static_cast<double>(data_int) / static_cast<double>(0x7fff);
171 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700172}
173
174DrivetrainInputReader::WheelAndThrottle
175PistolDrivetrainInputReader::GetWheelAndThrottle(
176 const ::aos::input::driver_station::Data &data) {
Austin Schuh2b1fce02018-03-02 20:05:20 -0800177 const double wheel =
178 -UnwrappedAxis(data, wheel_, wheel_low_);
179 const double wheel_velocity =
180 -UnwrappedAxis(data, wheel_velocity_high_, wheel_velocity_low_) * 50.0;
181 const double wheel_torque =
182 -UnwrappedAxis(data, wheel_torque_high_, wheel_torque_low_) / 2.0;
183
Austin Schuh876b4f02018-03-10 19:16:59 -0800184 double throttle =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800185 UnwrappedAxis(data, throttle_, throttle_low_);
186 const double throttle_velocity =
187 UnwrappedAxis(data, throttle_velocity_high_, throttle_velocity_low_) * 50.0;
188 const double throttle_torque =
189 UnwrappedAxis(data, throttle_torque_high_, throttle_torque_low_) / 2.0;
190
Austin Schuh876b4f02018-03-10 19:16:59 -0800191 // TODO(austin): Deal with haptics here.
192 if (throttle < 0) {
193 throttle = ::std::max(-1.0, throttle / 0.7);
194 }
195
James Kuszmaulc4eb1b22019-04-13 15:48:34 -0700196 if (data.IsPressed(slow_down_)) {
197 throttle *= 0.5;
198 }
199
Austin Schuh2b1fce02018-03-02 20:05:20 -0800200 if (!data.GetControlBit(ControlBit::kEnabled)) {
201 high_gear_ = default_high_gear_;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700202 }
203
Austin Schuh2b1fce02018-03-02 20:05:20 -0800204 if (data.PosEdge(shift_low_)) {
205 high_gear_ = false;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700206 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700207
Austin Schuh2b1fce02018-03-02 20:05:20 -0800208 if (data.PosEdge(shift_high_)) {
209 high_gear_ = true;
210 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700211
Austin Schuh2b1fce02018-03-02 20:05:20 -0800212 return DrivetrainInputReader::WheelAndThrottle{
213 wheel, wheel_velocity, wheel_torque,
214 throttle, throttle_velocity, throttle_torque,
215 high_gear_};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700216}
217
218DrivetrainInputReader::WheelAndThrottle
219XboxDrivetrainInputReader::GetWheelAndThrottle(
220 const ::aos::input::driver_station::Data &data) {
221 // xbox
222 constexpr double kWheelDeadband = 0.05;
223 constexpr double kThrottleDeadband = 0.05;
224 const double wheel =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800225 aos::Deadband(-data.GetAxis(wheel_), kWheelDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700226
227 const double unmodified_throttle =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800228 aos::Deadband(-data.GetAxis(throttle_), kThrottleDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700229
230 // Apply a sin function that's scaled to make it feel better.
231 constexpr double throttle_range = M_PI_2 * 0.9;
232
233 double throttle = ::std::sin(throttle_range * unmodified_throttle) /
234 ::std::sin(throttle_range);
235 throttle = ::std::sin(throttle_range * throttle) / ::std::sin(throttle_range);
236 throttle = 2.0 * unmodified_throttle - throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -0800237 return DrivetrainInputReader::WheelAndThrottle{wheel, 0.0, 0.0, throttle,
238 0.0, 0.0, true};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700239}
240
241std::unique_ptr<SteeringWheelDrivetrainInputReader>
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700242SteeringWheelDrivetrainInputReader::Make(::aos::EventLoop *event_loop,
243 bool default_high_gear) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700244 const JoystickAxis kSteeringWheel(1, 1), kDriveThrottle(2, 2);
245 const ButtonLocation kQuickTurn(1, 5);
246 const ButtonLocation kTurn1(1, 7);
247 const ButtonLocation kTurn2(1, 11);
248 std::unique_ptr<SteeringWheelDrivetrainInputReader> result(
James Kuszmaul8bad2412019-03-10 10:47:56 -0700249 new SteeringWheelDrivetrainInputReader(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700250 event_loop, kSteeringWheel, kDriveThrottle, kQuickTurn, kTurn1,
James Kuszmaul8bad2412019-03-10 10:47:56 -0700251 TurnButtonUse::kControlLoopDriving, kTurn2,
252 TurnButtonUse::kControlLoopDriving));
Sabina Davis82b19182017-11-10 09:30:25 -0800253 result.get()->set_default_high_gear(default_high_gear);
254
Sabina Davis92d2efa2017-11-04 22:35:25 -0700255 return result;
256}
257
Austin Schuh2b1fce02018-03-02 20:05:20 -0800258std::unique_ptr<PistolDrivetrainInputReader> PistolDrivetrainInputReader::Make(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700259 ::aos::EventLoop *event_loop, bool default_high_gear,
260 TopButtonUse top_button_use) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700261 // Pistol Grip controller
Austin Schuh2b1fce02018-03-02 20:05:20 -0800262 const JoystickAxis kTriggerHigh(1, 1), kTriggerLow(1, 4),
263 kTriggerVelocityHigh(1, 2), kTriggerVelocityLow(1, 5),
264 kTriggerTorqueHigh(1, 3), kTriggerTorqueLow(1, 6);
265
266 const JoystickAxis kWheelHigh(2, 1), kWheelLow(2, 4),
267 kWheelVelocityHigh(2, 2), kWheelVelocityLow(2, 5), kWheelTorqueHigh(2, 3),
268 kWheelTorqueLow(2, 6);
269
Austin Schuhe8a54c02018-03-05 00:25:58 -0800270 const ButtonLocation kQuickTurn(1, 3);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700271
James Kuszmaul8bad2412019-03-10 10:47:56 -0700272 const ButtonLocation TopButton(1, 1);
273 const ButtonLocation SecondButton(1, 2);
James Kuszmaulc4eb1b22019-04-13 15:48:34 -0700274 const ButtonLocation BottomButton(1, 4);
James Kuszmaul8bad2412019-03-10 10:47:56 -0700275 // Non-existant button for nops.
276 const ButtonLocation DummyButton(1, 10);
277
278 // TODO(james): Make a copy assignment operator for ButtonLocation so we don't
279 // have to shoehorn in these ternary operators.
Austin Schuh48d3a962019-03-17 18:12:32 -0700280 const ButtonLocation kTurn1 = (top_button_use == TopButtonUse::kLineFollow)
281 ? SecondButton
282 : DummyButton;
283 // Turn2 does closed loop driving.
284 const ButtonLocation kTurn2 =
James Kuszmaul8bad2412019-03-10 10:47:56 -0700285 (top_button_use == TopButtonUse::kLineFollow) ? TopButton : DummyButton;
Austin Schuh48d3a962019-03-17 18:12:32 -0700286
James Kuszmaul8bad2412019-03-10 10:47:56 -0700287 const ButtonLocation kShiftHigh =
288 (top_button_use == TopButtonUse::kShift) ? TopButton : DummyButton;
289 const ButtonLocation kShiftLow =
290 (top_button_use == TopButtonUse::kShift) ? SecondButton : DummyButton;
291
Sabina Davis92d2efa2017-11-04 22:35:25 -0700292 std::unique_ptr<PistolDrivetrainInputReader> result(
Austin Schuh2b1fce02018-03-02 20:05:20 -0800293 new PistolDrivetrainInputReader(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700294 event_loop, kWheelHigh, kWheelLow, kTriggerVelocityHigh,
295 kTriggerVelocityLow, kTriggerTorqueHigh, kTriggerTorqueLow,
296 kTriggerHigh, kTriggerLow, kWheelVelocityHigh, kWheelVelocityLow,
297 kWheelTorqueHigh, kWheelTorqueLow, kQuickTurn, kShiftHigh, kShiftLow,
298 kTurn1, kTurn2, BottomButton));
Austin Schuh2b1fce02018-03-02 20:05:20 -0800299
300 result->set_default_high_gear(default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700301 return result;
302}
303
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700304std::unique_ptr<XboxDrivetrainInputReader> XboxDrivetrainInputReader::Make(
305 ::aos::EventLoop *event_loop) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700306 // xbox
307 const JoystickAxis kSteeringWheel(1, 5), kDriveThrottle(1, 2);
308 const ButtonLocation kQuickTurn(1, 5);
309
310 // Nop
311 const ButtonLocation kTurn1(1, 1);
312 const ButtonLocation kTurn2(1, 2);
313
314 std::unique_ptr<XboxDrivetrainInputReader> result(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700315 new XboxDrivetrainInputReader(event_loop, kSteeringWheel, kDriveThrottle,
316 kQuickTurn, kTurn1,
317 TurnButtonUse::kControlLoopDriving, kTurn2,
James Kuszmaul8bad2412019-03-10 10:47:56 -0700318 TurnButtonUse::kControlLoopDriving));
Sabina Davis92d2efa2017-11-04 22:35:25 -0700319 return result;
320}
321::std::unique_ptr<DrivetrainInputReader> DrivetrainInputReader::Make(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700322 ::aos::EventLoop *event_loop, InputType type,
Alex Perrycb7da4b2019-08-28 19:35:56 -0700323 const drivetrain::DrivetrainConfig<double> &dt_config) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700324 std::unique_ptr<DrivetrainInputReader> drivetrain_input_reader;
325
326 using InputType = DrivetrainInputReader::InputType;
Sabina Davis82b19182017-11-10 09:30:25 -0800327
Sabina Davis92d2efa2017-11-04 22:35:25 -0700328 switch (type) {
329 case InputType::kSteeringWheel:
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700330 drivetrain_input_reader = SteeringWheelDrivetrainInputReader::Make(
331 event_loop, dt_config.default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700332 break;
333 case InputType::kPistol:
James Kuszmaul8bad2412019-03-10 10:47:56 -0700334 drivetrain_input_reader = PistolDrivetrainInputReader::Make(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700335 event_loop, dt_config.default_high_gear,
James Kuszmaul8bad2412019-03-10 10:47:56 -0700336 dt_config.pistol_grip_shift_enables_line_follow
337 ? PistolDrivetrainInputReader::TopButtonUse::kLineFollow
338 : PistolDrivetrainInputReader::TopButtonUse::kShift);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700339 break;
340 case InputType::kXbox:
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700341 drivetrain_input_reader = XboxDrivetrainInputReader::Make(event_loop);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700342 break;
343 }
344 return drivetrain_input_reader;
345}
346
347} // namespace input
348} // namespace aos