blob: 8c0fa6bd0f262ba8206f394deb9bc9a9ad83178f [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"
Sabina Davis92d2efa2017-11-04 22:35:25 -070011#include "frc971/control_loops/drivetrain/drivetrain.q.h"
12
13using ::frc971::control_loops::drivetrain_queue;
14using ::aos::input::driver_station::ButtonLocation;
15using ::aos::input::driver_station::ControlBit;
16using ::aos::input::driver_station::JoystickAxis;
17using ::aos::input::driver_station::POVLocation;
18
19namespace aos {
20namespace input {
21
Sabina Davis82b19182017-11-10 09:30:25 -080022const ButtonLocation kShiftHigh(2, 3), kShiftHigh2(2, 2), kShiftLow(2, 1);
23
Sabina Davis92d2efa2017-11-04 22:35:25 -070024void DrivetrainInputReader::HandleDrivetrain(
25 const ::aos::input::driver_station::Data &data) {
Sabina Davis92d2efa2017-11-04 22:35:25 -070026 const auto wheel_and_throttle = GetWheelAndThrottle(data);
27 const double wheel = wheel_and_throttle.wheel;
Austin Schuh2b1fce02018-03-02 20:05:20 -080028 const double wheel_velocity = wheel_and_throttle.wheel_velocity;
29 const double wheel_torque = wheel_and_throttle.wheel_torque;
Sabina Davis92d2efa2017-11-04 22:35:25 -070030 const double throttle = wheel_and_throttle.throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -080031 const double throttle_velocity = wheel_and_throttle.throttle_velocity;
32 const double throttle_torque = wheel_and_throttle.throttle_torque;
Sabina Davis82b19182017-11-10 09:30:25 -080033 const bool high_gear = wheel_and_throttle.high_gear;
Sabina Davis92d2efa2017-11-04 22:35:25 -070034
35 drivetrain_queue.status.FetchLatest();
36 if (drivetrain_queue.status.get()) {
37 robot_velocity_ = drivetrain_queue.status->robot_speed;
38 }
39
Austin Schuha250b2d2019-05-27 16:14:02 -070040 // If we have a vision align function, and it is in control, don't run the
41 // normal driving code.
42 if (vision_align_fn_) {
43 if (vision_align_fn_(data)) {
44 return;
45 }
46 }
47
James Kuszmaul8bad2412019-03-10 10:47:56 -070048 bool is_control_loop_driving = false;
49 bool is_line_following = false;
50
51 if (data.IsPressed(turn1_)) {
52 switch (turn1_use_) {
53 case TurnButtonUse::kControlLoopDriving:
54 is_control_loop_driving = true;
55 break;
56 case TurnButtonUse::kLineFollow:
57 is_line_following = true;
58 break;
59 }
60 }
61
62 if (data.IsPressed(turn2_)) {
63 switch (turn2_use_) {
64 case TurnButtonUse::kControlLoopDriving:
65 is_control_loop_driving = true;
66 break;
67 case TurnButtonUse::kLineFollow:
68 is_line_following = true;
69 break;
70 }
71 }
72
Austin Schuh48d3a962019-03-17 18:12:32 -070073 if (drivetrain_queue.status.get()) {
74 if (is_control_loop_driving && !last_is_control_loop_driving_) {
Austin Schuhf9202e82019-03-22 21:55:11 -070075 left_goal_ = drivetrain_queue.status->estimated_left_position +
76 wheel * wheel_multiplier_;
77 right_goal_ = drivetrain_queue.status->estimated_right_position -
78 wheel * wheel_multiplier_;
Sabina Davis92d2efa2017-11-04 22:35:25 -070079 }
80 }
Austin Schuh48d3a962019-03-17 18:12:32 -070081
Sabina Davis92d2efa2017-11-04 22:35:25 -070082 const double current_left_goal =
83 left_goal_ - wheel * wheel_multiplier_ + throttle * 0.3;
84 const double current_right_goal =
85 right_goal_ + wheel * wheel_multiplier_ + throttle * 0.3;
Sabina Davis92d2efa2017-11-04 22:35:25 -070086 auto new_drivetrain_goal = drivetrain_queue.goal.MakeMessage();
Austin Schuh2b1fce02018-03-02 20:05:20 -080087 new_drivetrain_goal->wheel = wheel;
88 new_drivetrain_goal->wheel_velocity = wheel_velocity;
89 new_drivetrain_goal->wheel_torque = wheel_torque;
Sabina Davis92d2efa2017-11-04 22:35:25 -070090 new_drivetrain_goal->throttle = throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -080091 new_drivetrain_goal->throttle_velocity = throttle_velocity;
92 new_drivetrain_goal->throttle_torque = throttle_torque;
Sabina Davis82b19182017-11-10 09:30:25 -080093 new_drivetrain_goal->highgear = high_gear;
94 new_drivetrain_goal->quickturn = data.IsPressed(quick_turn_);
James Kuszmaul8bad2412019-03-10 10:47:56 -070095 new_drivetrain_goal->controller_type =
96 is_line_following ? 3 : (is_control_loop_driving ? 1 : 0);
Sabina Davis92d2efa2017-11-04 22:35:25 -070097 new_drivetrain_goal->left_goal = current_left_goal;
98 new_drivetrain_goal->right_goal = current_right_goal;
Sabina Davis92d2efa2017-11-04 22:35:25 -070099
100 new_drivetrain_goal->linear.max_velocity = 3.0;
101 new_drivetrain_goal->linear.max_acceleration = 20.0;
102
103 if (!new_drivetrain_goal.Send()) {
104 LOG(WARNING, "sending stick values failed\n");
105 }
Austin Schuh48d3a962019-03-17 18:12:32 -0700106
107 last_is_control_loop_driving_ = is_control_loop_driving;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700108}
109
110DrivetrainInputReader::WheelAndThrottle
111SteeringWheelDrivetrainInputReader::GetWheelAndThrottle(
112 const ::aos::input::driver_station::Data &data) {
Austin Schuh2b1fce02018-03-02 20:05:20 -0800113 const double wheel = -data.GetAxis(wheel_);
114 const double throttle = -data.GetAxis(throttle_);
Sabina Davis82b19182017-11-10 09:30:25 -0800115
116 if (!data.GetControlBit(ControlBit::kEnabled)) {
117 high_gear_ = default_high_gear_;
118 }
119
120 if (data.PosEdge(kShiftLow)) {
121 high_gear_ = false;
122 }
123
124 if (data.PosEdge(kShiftHigh) || data.PosEdge(kShiftHigh2)) {
125 high_gear_ = true;
126 }
127
Austin Schuh2b1fce02018-03-02 20:05:20 -0800128 return DrivetrainInputReader::WheelAndThrottle{
129 wheel, 0.0, 0.0, throttle, 0.0, 0.0, high_gear_};
130}
131
132double UnwrappedAxis(const ::aos::input::driver_station::Data &data,
133 const JoystickAxis &high_bits,
134 const JoystickAxis &low_bits) {
135 const float high_bits_data = data.GetAxis(high_bits);
136 const float low_bits_data = data.GetAxis(low_bits);
137 const int16_t high_bits_data_int =
138 (high_bits_data < 0.0f ? high_bits_data * 128.0f
139 : high_bits_data * 127.0f);
140 const int16_t low_bits_data_int =
141 (low_bits_data < 0.0f ? low_bits_data * 128.0f : low_bits_data * 127.0f);
142
143 const uint16_t high_bits_data_uint =
144 ((static_cast<uint16_t>(high_bits_data_int) & 0xff) + 0x80) & 0xff;
145 const uint16_t low_bits_data_uint =
146 ((static_cast<uint16_t>(low_bits_data_int) & 0xff) + 0x80) & 0xff;
147
148 const uint16_t data_uint = (high_bits_data_uint << 8) | low_bits_data_uint;
149
150 const int32_t data_int = static_cast<int32_t>(data_uint) - 0x8000;
151
152 if (data_int < 0) {
153 return static_cast<double>(data_int) / static_cast<double>(0x8000);
154 } else {
155 return static_cast<double>(data_int) / static_cast<double>(0x7fff);
156 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700157}
158
159DrivetrainInputReader::WheelAndThrottle
160PistolDrivetrainInputReader::GetWheelAndThrottle(
161 const ::aos::input::driver_station::Data &data) {
Austin Schuh2b1fce02018-03-02 20:05:20 -0800162 const double wheel =
163 -UnwrappedAxis(data, wheel_, wheel_low_);
164 const double wheel_velocity =
165 -UnwrappedAxis(data, wheel_velocity_high_, wheel_velocity_low_) * 50.0;
166 const double wheel_torque =
167 -UnwrappedAxis(data, wheel_torque_high_, wheel_torque_low_) / 2.0;
168
Austin Schuh876b4f02018-03-10 19:16:59 -0800169 double throttle =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800170 UnwrappedAxis(data, throttle_, throttle_low_);
171 const double throttle_velocity =
172 UnwrappedAxis(data, throttle_velocity_high_, throttle_velocity_low_) * 50.0;
173 const double throttle_torque =
174 UnwrappedAxis(data, throttle_torque_high_, throttle_torque_low_) / 2.0;
175
Austin Schuh876b4f02018-03-10 19:16:59 -0800176 // TODO(austin): Deal with haptics here.
177 if (throttle < 0) {
178 throttle = ::std::max(-1.0, throttle / 0.7);
179 }
180
James Kuszmaulc4eb1b22019-04-13 15:48:34 -0700181 if (data.IsPressed(slow_down_)) {
182 throttle *= 0.5;
183 }
184
Austin Schuh2b1fce02018-03-02 20:05:20 -0800185 if (!data.GetControlBit(ControlBit::kEnabled)) {
186 high_gear_ = default_high_gear_;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700187 }
188
Austin Schuh2b1fce02018-03-02 20:05:20 -0800189 if (data.PosEdge(shift_low_)) {
190 high_gear_ = false;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700191 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700192
Austin Schuh2b1fce02018-03-02 20:05:20 -0800193 if (data.PosEdge(shift_high_)) {
194 high_gear_ = true;
195 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700196
Austin Schuh2b1fce02018-03-02 20:05:20 -0800197 return DrivetrainInputReader::WheelAndThrottle{
198 wheel, wheel_velocity, wheel_torque,
199 throttle, throttle_velocity, throttle_torque,
200 high_gear_};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700201}
202
203DrivetrainInputReader::WheelAndThrottle
204XboxDrivetrainInputReader::GetWheelAndThrottle(
205 const ::aos::input::driver_station::Data &data) {
206 // xbox
207 constexpr double kWheelDeadband = 0.05;
208 constexpr double kThrottleDeadband = 0.05;
209 const double wheel =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800210 aos::Deadband(-data.GetAxis(wheel_), kWheelDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700211
212 const double unmodified_throttle =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800213 aos::Deadband(-data.GetAxis(throttle_), kThrottleDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700214
215 // Apply a sin function that's scaled to make it feel better.
216 constexpr double throttle_range = M_PI_2 * 0.9;
217
218 double throttle = ::std::sin(throttle_range * unmodified_throttle) /
219 ::std::sin(throttle_range);
220 throttle = ::std::sin(throttle_range * throttle) / ::std::sin(throttle_range);
221 throttle = 2.0 * unmodified_throttle - throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -0800222 return DrivetrainInputReader::WheelAndThrottle{wheel, 0.0, 0.0, throttle,
223 0.0, 0.0, true};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700224}
225
226std::unique_ptr<SteeringWheelDrivetrainInputReader>
Sabina Davis82b19182017-11-10 09:30:25 -0800227SteeringWheelDrivetrainInputReader::Make(bool default_high_gear) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700228 const JoystickAxis kSteeringWheel(1, 1), kDriveThrottle(2, 2);
229 const ButtonLocation kQuickTurn(1, 5);
230 const ButtonLocation kTurn1(1, 7);
231 const ButtonLocation kTurn2(1, 11);
232 std::unique_ptr<SteeringWheelDrivetrainInputReader> result(
James Kuszmaul8bad2412019-03-10 10:47:56 -0700233 new SteeringWheelDrivetrainInputReader(
234 kSteeringWheel, kDriveThrottle, kQuickTurn, kTurn1,
235 TurnButtonUse::kControlLoopDriving, kTurn2,
236 TurnButtonUse::kControlLoopDriving));
Sabina Davis82b19182017-11-10 09:30:25 -0800237 result.get()->set_default_high_gear(default_high_gear);
238
Sabina Davis92d2efa2017-11-04 22:35:25 -0700239 return result;
240}
241
Austin Schuh2b1fce02018-03-02 20:05:20 -0800242std::unique_ptr<PistolDrivetrainInputReader> PistolDrivetrainInputReader::Make(
James Kuszmaul8bad2412019-03-10 10:47:56 -0700243 bool default_high_gear, TopButtonUse top_button_use) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700244 // Pistol Grip controller
Austin Schuh2b1fce02018-03-02 20:05:20 -0800245 const JoystickAxis kTriggerHigh(1, 1), kTriggerLow(1, 4),
246 kTriggerVelocityHigh(1, 2), kTriggerVelocityLow(1, 5),
247 kTriggerTorqueHigh(1, 3), kTriggerTorqueLow(1, 6);
248
249 const JoystickAxis kWheelHigh(2, 1), kWheelLow(2, 4),
250 kWheelVelocityHigh(2, 2), kWheelVelocityLow(2, 5), kWheelTorqueHigh(2, 3),
251 kWheelTorqueLow(2, 6);
252
Austin Schuhe8a54c02018-03-05 00:25:58 -0800253 const ButtonLocation kQuickTurn(1, 3);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700254
James Kuszmaul8bad2412019-03-10 10:47:56 -0700255 const ButtonLocation TopButton(1, 1);
256 const ButtonLocation SecondButton(1, 2);
James Kuszmaulc4eb1b22019-04-13 15:48:34 -0700257 const ButtonLocation BottomButton(1, 4);
James Kuszmaul8bad2412019-03-10 10:47:56 -0700258 // Non-existant button for nops.
259 const ButtonLocation DummyButton(1, 10);
260
261 // TODO(james): Make a copy assignment operator for ButtonLocation so we don't
262 // have to shoehorn in these ternary operators.
Austin Schuh48d3a962019-03-17 18:12:32 -0700263 const ButtonLocation kTurn1 = (top_button_use == TopButtonUse::kLineFollow)
264 ? SecondButton
265 : DummyButton;
266 // Turn2 does closed loop driving.
267 const ButtonLocation kTurn2 =
James Kuszmaul8bad2412019-03-10 10:47:56 -0700268 (top_button_use == TopButtonUse::kLineFollow) ? TopButton : DummyButton;
Austin Schuh48d3a962019-03-17 18:12:32 -0700269
James Kuszmaul8bad2412019-03-10 10:47:56 -0700270 const ButtonLocation kShiftHigh =
271 (top_button_use == TopButtonUse::kShift) ? TopButton : DummyButton;
272 const ButtonLocation kShiftLow =
273 (top_button_use == TopButtonUse::kShift) ? SecondButton : DummyButton;
274
Sabina Davis92d2efa2017-11-04 22:35:25 -0700275 std::unique_ptr<PistolDrivetrainInputReader> result(
Austin Schuh2b1fce02018-03-02 20:05:20 -0800276 new PistolDrivetrainInputReader(
277 kWheelHigh, kWheelLow, kTriggerVelocityHigh, kTriggerVelocityLow,
278 kTriggerTorqueHigh, kTriggerTorqueLow, kTriggerHigh, kTriggerLow,
279 kWheelVelocityHigh, kWheelVelocityLow, kWheelTorqueHigh,
James Kuszmaulc4eb1b22019-04-13 15:48:34 -0700280 kWheelTorqueLow, kQuickTurn, kShiftHigh, kShiftLow, kTurn1, kTurn2,
281 BottomButton));
Austin Schuh2b1fce02018-03-02 20:05:20 -0800282
283 result->set_default_high_gear(default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700284 return result;
285}
286
287std::unique_ptr<XboxDrivetrainInputReader> XboxDrivetrainInputReader::Make() {
288 // xbox
289 const JoystickAxis kSteeringWheel(1, 5), kDriveThrottle(1, 2);
290 const ButtonLocation kQuickTurn(1, 5);
291
292 // Nop
293 const ButtonLocation kTurn1(1, 1);
294 const ButtonLocation kTurn2(1, 2);
295
296 std::unique_ptr<XboxDrivetrainInputReader> result(
297 new XboxDrivetrainInputReader(kSteeringWheel, kDriveThrottle, kQuickTurn,
James Kuszmaul8bad2412019-03-10 10:47:56 -0700298 kTurn1, TurnButtonUse::kControlLoopDriving,
299 kTurn2,
300 TurnButtonUse::kControlLoopDriving));
Sabina Davis92d2efa2017-11-04 22:35:25 -0700301 return result;
302}
303::std::unique_ptr<DrivetrainInputReader> DrivetrainInputReader::Make(
Sabina Davis82b19182017-11-10 09:30:25 -0800304 InputType type,
Austin Schuhbcce26a2018-03-26 23:41:24 -0700305 const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
306 &dt_config) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700307 std::unique_ptr<DrivetrainInputReader> drivetrain_input_reader;
308
309 using InputType = DrivetrainInputReader::InputType;
Sabina Davis82b19182017-11-10 09:30:25 -0800310
Sabina Davis92d2efa2017-11-04 22:35:25 -0700311 switch (type) {
312 case InputType::kSteeringWheel:
Sabina Davis82b19182017-11-10 09:30:25 -0800313 drivetrain_input_reader =
314 SteeringWheelDrivetrainInputReader::Make(dt_config.default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700315 break;
316 case InputType::kPistol:
James Kuszmaul8bad2412019-03-10 10:47:56 -0700317 drivetrain_input_reader = PistolDrivetrainInputReader::Make(
318 dt_config.default_high_gear,
319 dt_config.pistol_grip_shift_enables_line_follow
320 ? PistolDrivetrainInputReader::TopButtonUse::kLineFollow
321 : PistolDrivetrainInputReader::TopButtonUse::kShift);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700322 break;
323 case InputType::kXbox:
324 drivetrain_input_reader = XboxDrivetrainInputReader::Make();
325 break;
326 }
327 return drivetrain_input_reader;
328}
329
330} // namespace input
331} // namespace aos