blob: 631f97dc9129e3e1cd29b42a8b44c3d32af4b6bf [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
James Kuszmaul8bad2412019-03-10 10:47:56 -070040 bool is_control_loop_driving = false;
41 bool is_line_following = false;
42
43 if (data.IsPressed(turn1_)) {
44 switch (turn1_use_) {
45 case TurnButtonUse::kControlLoopDriving:
46 is_control_loop_driving = true;
47 break;
48 case TurnButtonUse::kLineFollow:
49 is_line_following = true;
50 break;
51 }
52 }
53
54 if (data.IsPressed(turn2_)) {
55 switch (turn2_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
Austin Schuh48d3a962019-03-17 18:12:32 -070065 if (drivetrain_queue.status.get()) {
66 if (is_control_loop_driving && !last_is_control_loop_driving_) {
Austin Schuhf9202e82019-03-22 21:55:11 -070067 left_goal_ = drivetrain_queue.status->estimated_left_position +
68 wheel * wheel_multiplier_;
69 right_goal_ = drivetrain_queue.status->estimated_right_position -
70 wheel * wheel_multiplier_;
Sabina Davis92d2efa2017-11-04 22:35:25 -070071 }
72 }
Austin Schuh48d3a962019-03-17 18:12:32 -070073
Sabina Davis92d2efa2017-11-04 22:35:25 -070074 const double current_left_goal =
75 left_goal_ - wheel * wheel_multiplier_ + throttle * 0.3;
76 const double current_right_goal =
77 right_goal_ + wheel * wheel_multiplier_ + throttle * 0.3;
Sabina Davis92d2efa2017-11-04 22:35:25 -070078 auto new_drivetrain_goal = drivetrain_queue.goal.MakeMessage();
Austin Schuh2b1fce02018-03-02 20:05:20 -080079 new_drivetrain_goal->wheel = wheel;
80 new_drivetrain_goal->wheel_velocity = wheel_velocity;
81 new_drivetrain_goal->wheel_torque = wheel_torque;
Sabina Davis92d2efa2017-11-04 22:35:25 -070082 new_drivetrain_goal->throttle = throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -080083 new_drivetrain_goal->throttle_velocity = throttle_velocity;
84 new_drivetrain_goal->throttle_torque = throttle_torque;
Sabina Davis82b19182017-11-10 09:30:25 -080085 new_drivetrain_goal->highgear = high_gear;
86 new_drivetrain_goal->quickturn = data.IsPressed(quick_turn_);
James Kuszmaul8bad2412019-03-10 10:47:56 -070087 new_drivetrain_goal->controller_type =
88 is_line_following ? 3 : (is_control_loop_driving ? 1 : 0);
Sabina Davis92d2efa2017-11-04 22:35:25 -070089 new_drivetrain_goal->left_goal = current_left_goal;
90 new_drivetrain_goal->right_goal = current_right_goal;
Sabina Davis92d2efa2017-11-04 22:35:25 -070091
92 new_drivetrain_goal->linear.max_velocity = 3.0;
93 new_drivetrain_goal->linear.max_acceleration = 20.0;
94
95 if (!new_drivetrain_goal.Send()) {
96 LOG(WARNING, "sending stick values failed\n");
97 }
Austin Schuh48d3a962019-03-17 18:12:32 -070098
99 last_is_control_loop_driving_ = is_control_loop_driving;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700100}
101
102DrivetrainInputReader::WheelAndThrottle
103SteeringWheelDrivetrainInputReader::GetWheelAndThrottle(
104 const ::aos::input::driver_station::Data &data) {
Austin Schuh2b1fce02018-03-02 20:05:20 -0800105 const double wheel = -data.GetAxis(wheel_);
106 const double throttle = -data.GetAxis(throttle_);
Sabina Davis82b19182017-11-10 09:30:25 -0800107
108 if (!data.GetControlBit(ControlBit::kEnabled)) {
109 high_gear_ = default_high_gear_;
110 }
111
112 if (data.PosEdge(kShiftLow)) {
113 high_gear_ = false;
114 }
115
116 if (data.PosEdge(kShiftHigh) || data.PosEdge(kShiftHigh2)) {
117 high_gear_ = true;
118 }
119
Austin Schuh2b1fce02018-03-02 20:05:20 -0800120 return DrivetrainInputReader::WheelAndThrottle{
121 wheel, 0.0, 0.0, throttle, 0.0, 0.0, high_gear_};
122}
123
124double UnwrappedAxis(const ::aos::input::driver_station::Data &data,
125 const JoystickAxis &high_bits,
126 const JoystickAxis &low_bits) {
127 const float high_bits_data = data.GetAxis(high_bits);
128 const float low_bits_data = data.GetAxis(low_bits);
129 const int16_t high_bits_data_int =
130 (high_bits_data < 0.0f ? high_bits_data * 128.0f
131 : high_bits_data * 127.0f);
132 const int16_t low_bits_data_int =
133 (low_bits_data < 0.0f ? low_bits_data * 128.0f : low_bits_data * 127.0f);
134
135 const uint16_t high_bits_data_uint =
136 ((static_cast<uint16_t>(high_bits_data_int) & 0xff) + 0x80) & 0xff;
137 const uint16_t low_bits_data_uint =
138 ((static_cast<uint16_t>(low_bits_data_int) & 0xff) + 0x80) & 0xff;
139
140 const uint16_t data_uint = (high_bits_data_uint << 8) | low_bits_data_uint;
141
142 const int32_t data_int = static_cast<int32_t>(data_uint) - 0x8000;
143
144 if (data_int < 0) {
145 return static_cast<double>(data_int) / static_cast<double>(0x8000);
146 } else {
147 return static_cast<double>(data_int) / static_cast<double>(0x7fff);
148 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700149}
150
151DrivetrainInputReader::WheelAndThrottle
152PistolDrivetrainInputReader::GetWheelAndThrottle(
153 const ::aos::input::driver_station::Data &data) {
Austin Schuh2b1fce02018-03-02 20:05:20 -0800154 const double wheel =
155 -UnwrappedAxis(data, wheel_, wheel_low_);
156 const double wheel_velocity =
157 -UnwrappedAxis(data, wheel_velocity_high_, wheel_velocity_low_) * 50.0;
158 const double wheel_torque =
159 -UnwrappedAxis(data, wheel_torque_high_, wheel_torque_low_) / 2.0;
160
Austin Schuh876b4f02018-03-10 19:16:59 -0800161 double throttle =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800162 UnwrappedAxis(data, throttle_, throttle_low_);
163 const double throttle_velocity =
164 UnwrappedAxis(data, throttle_velocity_high_, throttle_velocity_low_) * 50.0;
165 const double throttle_torque =
166 UnwrappedAxis(data, throttle_torque_high_, throttle_torque_low_) / 2.0;
167
Austin Schuh876b4f02018-03-10 19:16:59 -0800168 // TODO(austin): Deal with haptics here.
169 if (throttle < 0) {
170 throttle = ::std::max(-1.0, throttle / 0.7);
171 }
172
James Kuszmaulc4eb1b22019-04-13 15:48:34 -0700173 if (data.IsPressed(slow_down_)) {
174 throttle *= 0.5;
175 }
176
Austin Schuh2b1fce02018-03-02 20:05:20 -0800177 if (!data.GetControlBit(ControlBit::kEnabled)) {
178 high_gear_ = default_high_gear_;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700179 }
180
Austin Schuh2b1fce02018-03-02 20:05:20 -0800181 if (data.PosEdge(shift_low_)) {
182 high_gear_ = false;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700183 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700184
Austin Schuh2b1fce02018-03-02 20:05:20 -0800185 if (data.PosEdge(shift_high_)) {
186 high_gear_ = true;
187 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700188
Austin Schuh2b1fce02018-03-02 20:05:20 -0800189 return DrivetrainInputReader::WheelAndThrottle{
190 wheel, wheel_velocity, wheel_torque,
191 throttle, throttle_velocity, throttle_torque,
192 high_gear_};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700193}
194
195DrivetrainInputReader::WheelAndThrottle
196XboxDrivetrainInputReader::GetWheelAndThrottle(
197 const ::aos::input::driver_station::Data &data) {
198 // xbox
199 constexpr double kWheelDeadband = 0.05;
200 constexpr double kThrottleDeadband = 0.05;
201 const double wheel =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800202 aos::Deadband(-data.GetAxis(wheel_), kWheelDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700203
204 const double unmodified_throttle =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800205 aos::Deadband(-data.GetAxis(throttle_), kThrottleDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700206
207 // Apply a sin function that's scaled to make it feel better.
208 constexpr double throttle_range = M_PI_2 * 0.9;
209
210 double throttle = ::std::sin(throttle_range * unmodified_throttle) /
211 ::std::sin(throttle_range);
212 throttle = ::std::sin(throttle_range * throttle) / ::std::sin(throttle_range);
213 throttle = 2.0 * unmodified_throttle - throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -0800214 return DrivetrainInputReader::WheelAndThrottle{wheel, 0.0, 0.0, throttle,
215 0.0, 0.0, true};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700216}
217
218std::unique_ptr<SteeringWheelDrivetrainInputReader>
Sabina Davis82b19182017-11-10 09:30:25 -0800219SteeringWheelDrivetrainInputReader::Make(bool default_high_gear) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700220 const JoystickAxis kSteeringWheel(1, 1), kDriveThrottle(2, 2);
221 const ButtonLocation kQuickTurn(1, 5);
222 const ButtonLocation kTurn1(1, 7);
223 const ButtonLocation kTurn2(1, 11);
224 std::unique_ptr<SteeringWheelDrivetrainInputReader> result(
James Kuszmaul8bad2412019-03-10 10:47:56 -0700225 new SteeringWheelDrivetrainInputReader(
226 kSteeringWheel, kDriveThrottle, kQuickTurn, kTurn1,
227 TurnButtonUse::kControlLoopDriving, kTurn2,
228 TurnButtonUse::kControlLoopDriving));
Sabina Davis82b19182017-11-10 09:30:25 -0800229 result.get()->set_default_high_gear(default_high_gear);
230
Sabina Davis92d2efa2017-11-04 22:35:25 -0700231 return result;
232}
233
Austin Schuh2b1fce02018-03-02 20:05:20 -0800234std::unique_ptr<PistolDrivetrainInputReader> PistolDrivetrainInputReader::Make(
James Kuszmaul8bad2412019-03-10 10:47:56 -0700235 bool default_high_gear, TopButtonUse top_button_use) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700236 // Pistol Grip controller
Austin Schuh2b1fce02018-03-02 20:05:20 -0800237 const JoystickAxis kTriggerHigh(1, 1), kTriggerLow(1, 4),
238 kTriggerVelocityHigh(1, 2), kTriggerVelocityLow(1, 5),
239 kTriggerTorqueHigh(1, 3), kTriggerTorqueLow(1, 6);
240
241 const JoystickAxis kWheelHigh(2, 1), kWheelLow(2, 4),
242 kWheelVelocityHigh(2, 2), kWheelVelocityLow(2, 5), kWheelTorqueHigh(2, 3),
243 kWheelTorqueLow(2, 6);
244
Austin Schuhe8a54c02018-03-05 00:25:58 -0800245 const ButtonLocation kQuickTurn(1, 3);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700246
James Kuszmaul8bad2412019-03-10 10:47:56 -0700247 const ButtonLocation TopButton(1, 1);
248 const ButtonLocation SecondButton(1, 2);
James Kuszmaulc4eb1b22019-04-13 15:48:34 -0700249 const ButtonLocation BottomButton(1, 4);
James Kuszmaul8bad2412019-03-10 10:47:56 -0700250 // Non-existant button for nops.
251 const ButtonLocation DummyButton(1, 10);
252
253 // TODO(james): Make a copy assignment operator for ButtonLocation so we don't
254 // have to shoehorn in these ternary operators.
Austin Schuh48d3a962019-03-17 18:12:32 -0700255 const ButtonLocation kTurn1 = (top_button_use == TopButtonUse::kLineFollow)
256 ? SecondButton
257 : DummyButton;
258 // Turn2 does closed loop driving.
259 const ButtonLocation kTurn2 =
James Kuszmaul8bad2412019-03-10 10:47:56 -0700260 (top_button_use == TopButtonUse::kLineFollow) ? TopButton : DummyButton;
Austin Schuh48d3a962019-03-17 18:12:32 -0700261
James Kuszmaul8bad2412019-03-10 10:47:56 -0700262 const ButtonLocation kShiftHigh =
263 (top_button_use == TopButtonUse::kShift) ? TopButton : DummyButton;
264 const ButtonLocation kShiftLow =
265 (top_button_use == TopButtonUse::kShift) ? SecondButton : DummyButton;
266
Sabina Davis92d2efa2017-11-04 22:35:25 -0700267 std::unique_ptr<PistolDrivetrainInputReader> result(
Austin Schuh2b1fce02018-03-02 20:05:20 -0800268 new PistolDrivetrainInputReader(
269 kWheelHigh, kWheelLow, kTriggerVelocityHigh, kTriggerVelocityLow,
270 kTriggerTorqueHigh, kTriggerTorqueLow, kTriggerHigh, kTriggerLow,
271 kWheelVelocityHigh, kWheelVelocityLow, kWheelTorqueHigh,
James Kuszmaulc4eb1b22019-04-13 15:48:34 -0700272 kWheelTorqueLow, kQuickTurn, kShiftHigh, kShiftLow, kTurn1, kTurn2,
273 BottomButton));
Austin Schuh2b1fce02018-03-02 20:05:20 -0800274
275 result->set_default_high_gear(default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700276 return result;
277}
278
279std::unique_ptr<XboxDrivetrainInputReader> XboxDrivetrainInputReader::Make() {
280 // xbox
281 const JoystickAxis kSteeringWheel(1, 5), kDriveThrottle(1, 2);
282 const ButtonLocation kQuickTurn(1, 5);
283
284 // Nop
285 const ButtonLocation kTurn1(1, 1);
286 const ButtonLocation kTurn2(1, 2);
287
288 std::unique_ptr<XboxDrivetrainInputReader> result(
289 new XboxDrivetrainInputReader(kSteeringWheel, kDriveThrottle, kQuickTurn,
James Kuszmaul8bad2412019-03-10 10:47:56 -0700290 kTurn1, TurnButtonUse::kControlLoopDriving,
291 kTurn2,
292 TurnButtonUse::kControlLoopDriving));
Sabina Davis92d2efa2017-11-04 22:35:25 -0700293 return result;
294}
295::std::unique_ptr<DrivetrainInputReader> DrivetrainInputReader::Make(
Sabina Davis82b19182017-11-10 09:30:25 -0800296 InputType type,
Austin Schuhbcce26a2018-03-26 23:41:24 -0700297 const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
298 &dt_config) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700299 std::unique_ptr<DrivetrainInputReader> drivetrain_input_reader;
300
301 using InputType = DrivetrainInputReader::InputType;
Sabina Davis82b19182017-11-10 09:30:25 -0800302
Sabina Davis92d2efa2017-11-04 22:35:25 -0700303 switch (type) {
304 case InputType::kSteeringWheel:
Sabina Davis82b19182017-11-10 09:30:25 -0800305 drivetrain_input_reader =
306 SteeringWheelDrivetrainInputReader::Make(dt_config.default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700307 break;
308 case InputType::kPistol:
James Kuszmaul8bad2412019-03-10 10:47:56 -0700309 drivetrain_input_reader = PistolDrivetrainInputReader::Make(
310 dt_config.default_high_gear,
311 dt_config.pistol_grip_shift_enables_line_follow
312 ? PistolDrivetrainInputReader::TopButtonUse::kLineFollow
313 : PistolDrivetrainInputReader::TopButtonUse::kShift);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700314 break;
315 case InputType::kXbox:
316 drivetrain_input_reader = XboxDrivetrainInputReader::Make();
317 break;
318 }
319 return drivetrain_input_reader;
320}
321
322} // namespace input
323} // namespace aos