blob: a0bbf2cf9915aa845e35889c7ec0fa4989039706 [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
Sabina Davis92d2efa2017-11-04 22:35:25 -070013using ::aos::input::driver_station::ButtonLocation;
14using ::aos::input::driver_station::ControlBit;
15using ::aos::input::driver_station::JoystickAxis;
16using ::aos::input::driver_station::POVLocation;
17
18namespace aos {
19namespace input {
20
Sabina Davis82b19182017-11-10 09:30:25 -080021const ButtonLocation kShiftHigh(2, 3), kShiftHigh2(2, 2), kShiftLow(2, 1);
22
Sabina Davis92d2efa2017-11-04 22:35:25 -070023void DrivetrainInputReader::HandleDrivetrain(
24 const ::aos::input::driver_station::Data &data) {
Sabina Davis92d2efa2017-11-04 22:35:25 -070025 const auto wheel_and_throttle = GetWheelAndThrottle(data);
26 const double wheel = wheel_and_throttle.wheel;
Austin Schuh2b1fce02018-03-02 20:05:20 -080027 const double wheel_velocity = wheel_and_throttle.wheel_velocity;
28 const double wheel_torque = wheel_and_throttle.wheel_torque;
Sabina Davis92d2efa2017-11-04 22:35:25 -070029 const double throttle = wheel_and_throttle.throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -080030 const double throttle_velocity = wheel_and_throttle.throttle_velocity;
31 const double throttle_torque = wheel_and_throttle.throttle_torque;
Sabina Davis82b19182017-11-10 09:30:25 -080032 const bool high_gear = wheel_and_throttle.high_gear;
Sabina Davis92d2efa2017-11-04 22:35:25 -070033
Austin Schuhbd0a40f2019-06-30 14:56:31 -070034 drivetrain_status_fetcher_.Fetch();
35 if (drivetrain_status_fetcher_.get()) {
36 robot_velocity_ = drivetrain_status_fetcher_->robot_speed;
Sabina Davis92d2efa2017-11-04 22:35:25 -070037 }
38
Austin Schuha250b2d2019-05-27 16:14:02 -070039 // If we have a vision align function, and it is in control, don't run the
40 // normal driving code.
41 if (vision_align_fn_) {
42 if (vision_align_fn_(data)) {
43 return;
44 }
45 }
46
James Kuszmaul8bad2412019-03-10 10:47:56 -070047 bool is_control_loop_driving = false;
48 bool is_line_following = false;
49
50 if (data.IsPressed(turn1_)) {
51 switch (turn1_use_) {
52 case TurnButtonUse::kControlLoopDriving:
53 is_control_loop_driving = true;
54 break;
55 case TurnButtonUse::kLineFollow:
56 is_line_following = true;
57 break;
58 }
59 }
60
61 if (data.IsPressed(turn2_)) {
62 switch (turn2_use_) {
63 case TurnButtonUse::kControlLoopDriving:
64 is_control_loop_driving = true;
65 break;
66 case TurnButtonUse::kLineFollow:
67 is_line_following = true;
68 break;
69 }
70 }
71
Austin Schuhbd0a40f2019-06-30 14:56:31 -070072 if (drivetrain_status_fetcher_.get()) {
Austin Schuh48d3a962019-03-17 18:12:32 -070073 if (is_control_loop_driving && !last_is_control_loop_driving_) {
Austin Schuhbd0a40f2019-06-30 14:56:31 -070074 left_goal_ = drivetrain_status_fetcher_->estimated_left_position +
Austin Schuhf9202e82019-03-22 21:55:11 -070075 wheel * wheel_multiplier_;
Austin Schuhbd0a40f2019-06-30 14:56:31 -070076 right_goal_ = drivetrain_status_fetcher_->estimated_right_position -
Austin Schuhf9202e82019-03-22 21:55:11 -070077 wheel * wheel_multiplier_;
Sabina Davis92d2efa2017-11-04 22:35:25 -070078 }
79 }
Austin Schuh48d3a962019-03-17 18:12:32 -070080
Sabina Davis92d2efa2017-11-04 22:35:25 -070081 const double current_left_goal =
82 left_goal_ - wheel * wheel_multiplier_ + throttle * 0.3;
83 const double current_right_goal =
84 right_goal_ + wheel * wheel_multiplier_ + throttle * 0.3;
Austin Schuhbd0a40f2019-06-30 14:56:31 -070085 auto new_drivetrain_goal = drivetrain_goal_sender_.MakeMessage();
Austin Schuh2b1fce02018-03-02 20:05:20 -080086 new_drivetrain_goal->wheel = wheel;
87 new_drivetrain_goal->wheel_velocity = wheel_velocity;
88 new_drivetrain_goal->wheel_torque = wheel_torque;
Sabina Davis92d2efa2017-11-04 22:35:25 -070089 new_drivetrain_goal->throttle = throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -080090 new_drivetrain_goal->throttle_velocity = throttle_velocity;
91 new_drivetrain_goal->throttle_torque = throttle_torque;
Sabina Davis82b19182017-11-10 09:30:25 -080092 new_drivetrain_goal->highgear = high_gear;
93 new_drivetrain_goal->quickturn = data.IsPressed(quick_turn_);
James Kuszmaul8bad2412019-03-10 10:47:56 -070094 new_drivetrain_goal->controller_type =
95 is_line_following ? 3 : (is_control_loop_driving ? 1 : 0);
Sabina Davis92d2efa2017-11-04 22:35:25 -070096 new_drivetrain_goal->left_goal = current_left_goal;
97 new_drivetrain_goal->right_goal = current_right_goal;
Sabina Davis92d2efa2017-11-04 22:35:25 -070098
99 new_drivetrain_goal->linear.max_velocity = 3.0;
100 new_drivetrain_goal->linear.max_acceleration = 20.0;
101
102 if (!new_drivetrain_goal.Send()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700103 AOS_LOG(WARNING, "sending stick values failed\n");
Sabina Davis92d2efa2017-11-04 22:35:25 -0700104 }
Austin Schuh48d3a962019-03-17 18:12:32 -0700105
106 last_is_control_loop_driving_ = is_control_loop_driving;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700107}
108
109DrivetrainInputReader::WheelAndThrottle
110SteeringWheelDrivetrainInputReader::GetWheelAndThrottle(
111 const ::aos::input::driver_station::Data &data) {
Austin Schuh2b1fce02018-03-02 20:05:20 -0800112 const double wheel = -data.GetAxis(wheel_);
113 const double throttle = -data.GetAxis(throttle_);
Sabina Davis82b19182017-11-10 09:30:25 -0800114
115 if (!data.GetControlBit(ControlBit::kEnabled)) {
116 high_gear_ = default_high_gear_;
117 }
118
119 if (data.PosEdge(kShiftLow)) {
120 high_gear_ = false;
121 }
122
123 if (data.PosEdge(kShiftHigh) || data.PosEdge(kShiftHigh2)) {
124 high_gear_ = true;
125 }
126
Austin Schuh2b1fce02018-03-02 20:05:20 -0800127 return DrivetrainInputReader::WheelAndThrottle{
128 wheel, 0.0, 0.0, throttle, 0.0, 0.0, high_gear_};
129}
130
131double UnwrappedAxis(const ::aos::input::driver_station::Data &data,
132 const JoystickAxis &high_bits,
133 const JoystickAxis &low_bits) {
134 const float high_bits_data = data.GetAxis(high_bits);
135 const float low_bits_data = data.GetAxis(low_bits);
136 const int16_t high_bits_data_int =
137 (high_bits_data < 0.0f ? high_bits_data * 128.0f
138 : high_bits_data * 127.0f);
139 const int16_t low_bits_data_int =
140 (low_bits_data < 0.0f ? low_bits_data * 128.0f : low_bits_data * 127.0f);
141
142 const uint16_t high_bits_data_uint =
143 ((static_cast<uint16_t>(high_bits_data_int) & 0xff) + 0x80) & 0xff;
144 const uint16_t low_bits_data_uint =
145 ((static_cast<uint16_t>(low_bits_data_int) & 0xff) + 0x80) & 0xff;
146
147 const uint16_t data_uint = (high_bits_data_uint << 8) | low_bits_data_uint;
148
149 const int32_t data_int = static_cast<int32_t>(data_uint) - 0x8000;
150
151 if (data_int < 0) {
152 return static_cast<double>(data_int) / static_cast<double>(0x8000);
153 } else {
154 return static_cast<double>(data_int) / static_cast<double>(0x7fff);
155 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700156}
157
158DrivetrainInputReader::WheelAndThrottle
159PistolDrivetrainInputReader::GetWheelAndThrottle(
160 const ::aos::input::driver_station::Data &data) {
Austin Schuh2b1fce02018-03-02 20:05:20 -0800161 const double wheel =
162 -UnwrappedAxis(data, wheel_, wheel_low_);
163 const double wheel_velocity =
164 -UnwrappedAxis(data, wheel_velocity_high_, wheel_velocity_low_) * 50.0;
165 const double wheel_torque =
166 -UnwrappedAxis(data, wheel_torque_high_, wheel_torque_low_) / 2.0;
167
Austin Schuh876b4f02018-03-10 19:16:59 -0800168 double throttle =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800169 UnwrappedAxis(data, throttle_, throttle_low_);
170 const double throttle_velocity =
171 UnwrappedAxis(data, throttle_velocity_high_, throttle_velocity_low_) * 50.0;
172 const double throttle_torque =
173 UnwrappedAxis(data, throttle_torque_high_, throttle_torque_low_) / 2.0;
174
Austin Schuh876b4f02018-03-10 19:16:59 -0800175 // TODO(austin): Deal with haptics here.
176 if (throttle < 0) {
177 throttle = ::std::max(-1.0, throttle / 0.7);
178 }
179
James Kuszmaulc4eb1b22019-04-13 15:48:34 -0700180 if (data.IsPressed(slow_down_)) {
181 throttle *= 0.5;
182 }
183
Austin Schuh2b1fce02018-03-02 20:05:20 -0800184 if (!data.GetControlBit(ControlBit::kEnabled)) {
185 high_gear_ = default_high_gear_;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700186 }
187
Austin Schuh2b1fce02018-03-02 20:05:20 -0800188 if (data.PosEdge(shift_low_)) {
189 high_gear_ = false;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700190 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700191
Austin Schuh2b1fce02018-03-02 20:05:20 -0800192 if (data.PosEdge(shift_high_)) {
193 high_gear_ = true;
194 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700195
Austin Schuh2b1fce02018-03-02 20:05:20 -0800196 return DrivetrainInputReader::WheelAndThrottle{
197 wheel, wheel_velocity, wheel_torque,
198 throttle, throttle_velocity, throttle_torque,
199 high_gear_};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700200}
201
202DrivetrainInputReader::WheelAndThrottle
203XboxDrivetrainInputReader::GetWheelAndThrottle(
204 const ::aos::input::driver_station::Data &data) {
205 // xbox
206 constexpr double kWheelDeadband = 0.05;
207 constexpr double kThrottleDeadband = 0.05;
208 const double wheel =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800209 aos::Deadband(-data.GetAxis(wheel_), kWheelDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700210
211 const double unmodified_throttle =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800212 aos::Deadband(-data.GetAxis(throttle_), kThrottleDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700213
214 // Apply a sin function that's scaled to make it feel better.
215 constexpr double throttle_range = M_PI_2 * 0.9;
216
217 double throttle = ::std::sin(throttle_range * unmodified_throttle) /
218 ::std::sin(throttle_range);
219 throttle = ::std::sin(throttle_range * throttle) / ::std::sin(throttle_range);
220 throttle = 2.0 * unmodified_throttle - throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -0800221 return DrivetrainInputReader::WheelAndThrottle{wheel, 0.0, 0.0, throttle,
222 0.0, 0.0, true};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700223}
224
225std::unique_ptr<SteeringWheelDrivetrainInputReader>
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700226SteeringWheelDrivetrainInputReader::Make(::aos::EventLoop *event_loop,
227 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(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700234 event_loop, kSteeringWheel, kDriveThrottle, kQuickTurn, kTurn1,
James Kuszmaul8bad2412019-03-10 10:47:56 -0700235 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(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700243 ::aos::EventLoop *event_loop, bool default_high_gear,
244 TopButtonUse top_button_use) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700245 // Pistol Grip controller
Austin Schuh2b1fce02018-03-02 20:05:20 -0800246 const JoystickAxis kTriggerHigh(1, 1), kTriggerLow(1, 4),
247 kTriggerVelocityHigh(1, 2), kTriggerVelocityLow(1, 5),
248 kTriggerTorqueHigh(1, 3), kTriggerTorqueLow(1, 6);
249
250 const JoystickAxis kWheelHigh(2, 1), kWheelLow(2, 4),
251 kWheelVelocityHigh(2, 2), kWheelVelocityLow(2, 5), kWheelTorqueHigh(2, 3),
252 kWheelTorqueLow(2, 6);
253
Austin Schuhe8a54c02018-03-05 00:25:58 -0800254 const ButtonLocation kQuickTurn(1, 3);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700255
James Kuszmaul8bad2412019-03-10 10:47:56 -0700256 const ButtonLocation TopButton(1, 1);
257 const ButtonLocation SecondButton(1, 2);
James Kuszmaulc4eb1b22019-04-13 15:48:34 -0700258 const ButtonLocation BottomButton(1, 4);
James Kuszmaul8bad2412019-03-10 10:47:56 -0700259 // Non-existant button for nops.
260 const ButtonLocation DummyButton(1, 10);
261
262 // TODO(james): Make a copy assignment operator for ButtonLocation so we don't
263 // have to shoehorn in these ternary operators.
Austin Schuh48d3a962019-03-17 18:12:32 -0700264 const ButtonLocation kTurn1 = (top_button_use == TopButtonUse::kLineFollow)
265 ? SecondButton
266 : DummyButton;
267 // Turn2 does closed loop driving.
268 const ButtonLocation kTurn2 =
James Kuszmaul8bad2412019-03-10 10:47:56 -0700269 (top_button_use == TopButtonUse::kLineFollow) ? TopButton : DummyButton;
Austin Schuh48d3a962019-03-17 18:12:32 -0700270
James Kuszmaul8bad2412019-03-10 10:47:56 -0700271 const ButtonLocation kShiftHigh =
272 (top_button_use == TopButtonUse::kShift) ? TopButton : DummyButton;
273 const ButtonLocation kShiftLow =
274 (top_button_use == TopButtonUse::kShift) ? SecondButton : DummyButton;
275
Sabina Davis92d2efa2017-11-04 22:35:25 -0700276 std::unique_ptr<PistolDrivetrainInputReader> result(
Austin Schuh2b1fce02018-03-02 20:05:20 -0800277 new PistolDrivetrainInputReader(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700278 event_loop, kWheelHigh, kWheelLow, kTriggerVelocityHigh,
279 kTriggerVelocityLow, kTriggerTorqueHigh, kTriggerTorqueLow,
280 kTriggerHigh, kTriggerLow, kWheelVelocityHigh, kWheelVelocityLow,
281 kWheelTorqueHigh, kWheelTorqueLow, kQuickTurn, kShiftHigh, kShiftLow,
282 kTurn1, kTurn2, BottomButton));
Austin Schuh2b1fce02018-03-02 20:05:20 -0800283
284 result->set_default_high_gear(default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700285 return result;
286}
287
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700288std::unique_ptr<XboxDrivetrainInputReader> XboxDrivetrainInputReader::Make(
289 ::aos::EventLoop *event_loop) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700290 // xbox
291 const JoystickAxis kSteeringWheel(1, 5), kDriveThrottle(1, 2);
292 const ButtonLocation kQuickTurn(1, 5);
293
294 // Nop
295 const ButtonLocation kTurn1(1, 1);
296 const ButtonLocation kTurn2(1, 2);
297
298 std::unique_ptr<XboxDrivetrainInputReader> result(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700299 new XboxDrivetrainInputReader(event_loop, kSteeringWheel, kDriveThrottle,
300 kQuickTurn, kTurn1,
301 TurnButtonUse::kControlLoopDriving, kTurn2,
James Kuszmaul8bad2412019-03-10 10:47:56 -0700302 TurnButtonUse::kControlLoopDriving));
Sabina Davis92d2efa2017-11-04 22:35:25 -0700303 return result;
304}
305::std::unique_ptr<DrivetrainInputReader> DrivetrainInputReader::Make(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700306 ::aos::EventLoop *event_loop, InputType type,
Austin Schuhbcce26a2018-03-26 23:41:24 -0700307 const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
308 &dt_config) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700309 std::unique_ptr<DrivetrainInputReader> drivetrain_input_reader;
310
311 using InputType = DrivetrainInputReader::InputType;
Sabina Davis82b19182017-11-10 09:30:25 -0800312
Sabina Davis92d2efa2017-11-04 22:35:25 -0700313 switch (type) {
314 case InputType::kSteeringWheel:
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700315 drivetrain_input_reader = SteeringWheelDrivetrainInputReader::Make(
316 event_loop, dt_config.default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700317 break;
318 case InputType::kPistol:
James Kuszmaul8bad2412019-03-10 10:47:56 -0700319 drivetrain_input_reader = PistolDrivetrainInputReader::Make(
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700320 event_loop, dt_config.default_high_gear,
James Kuszmaul8bad2412019-03-10 10:47:56 -0700321 dt_config.pistol_grip_shift_enables_line_follow
322 ? PistolDrivetrainInputReader::TopButtonUse::kLineFollow
323 : PistolDrivetrainInputReader::TopButtonUse::kShift);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700324 break;
325 case InputType::kXbox:
Austin Schuhbd0a40f2019-06-30 14:56:31 -0700326 drivetrain_input_reader = XboxDrivetrainInputReader::Make(event_loop);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700327 break;
328 }
329 return drivetrain_input_reader;
330}
331
332} // namespace input
333} // namespace aos