blob: f9cc45dcd248a61d03216f55a09134550b3a97c6 [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_) {
Sabina Davis92d2efa2017-11-04 22:35:25 -070067 left_goal_ = drivetrain_queue.status->estimated_left_position;
68 right_goal_ = drivetrain_queue.status->estimated_right_position;
69 }
70 }
Austin Schuh48d3a962019-03-17 18:12:32 -070071
Sabina Davis92d2efa2017-11-04 22:35:25 -070072 const double current_left_goal =
73 left_goal_ - wheel * wheel_multiplier_ + throttle * 0.3;
74 const double current_right_goal =
75 right_goal_ + wheel * wheel_multiplier_ + throttle * 0.3;
Sabina Davis92d2efa2017-11-04 22:35:25 -070076 auto new_drivetrain_goal = drivetrain_queue.goal.MakeMessage();
Austin Schuh2b1fce02018-03-02 20:05:20 -080077 new_drivetrain_goal->wheel = wheel;
78 new_drivetrain_goal->wheel_velocity = wheel_velocity;
79 new_drivetrain_goal->wheel_torque = wheel_torque;
Sabina Davis92d2efa2017-11-04 22:35:25 -070080 new_drivetrain_goal->throttle = throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -080081 new_drivetrain_goal->throttle_velocity = throttle_velocity;
82 new_drivetrain_goal->throttle_torque = throttle_torque;
Sabina Davis82b19182017-11-10 09:30:25 -080083 new_drivetrain_goal->highgear = high_gear;
84 new_drivetrain_goal->quickturn = data.IsPressed(quick_turn_);
James Kuszmaul8bad2412019-03-10 10:47:56 -070085 new_drivetrain_goal->controller_type =
86 is_line_following ? 3 : (is_control_loop_driving ? 1 : 0);
Sabina Davis92d2efa2017-11-04 22:35:25 -070087 new_drivetrain_goal->left_goal = current_left_goal;
88 new_drivetrain_goal->right_goal = current_right_goal;
Sabina Davis92d2efa2017-11-04 22:35:25 -070089
90 new_drivetrain_goal->linear.max_velocity = 3.0;
91 new_drivetrain_goal->linear.max_acceleration = 20.0;
92
93 if (!new_drivetrain_goal.Send()) {
94 LOG(WARNING, "sending stick values failed\n");
95 }
Austin Schuh48d3a962019-03-17 18:12:32 -070096
97 last_is_control_loop_driving_ = is_control_loop_driving;
Sabina Davis92d2efa2017-11-04 22:35:25 -070098}
99
100DrivetrainInputReader::WheelAndThrottle
101SteeringWheelDrivetrainInputReader::GetWheelAndThrottle(
102 const ::aos::input::driver_station::Data &data) {
Austin Schuh2b1fce02018-03-02 20:05:20 -0800103 const double wheel = -data.GetAxis(wheel_);
104 const double throttle = -data.GetAxis(throttle_);
Sabina Davis82b19182017-11-10 09:30:25 -0800105
106 if (!data.GetControlBit(ControlBit::kEnabled)) {
107 high_gear_ = default_high_gear_;
108 }
109
110 if (data.PosEdge(kShiftLow)) {
111 high_gear_ = false;
112 }
113
114 if (data.PosEdge(kShiftHigh) || data.PosEdge(kShiftHigh2)) {
115 high_gear_ = true;
116 }
117
Austin Schuh2b1fce02018-03-02 20:05:20 -0800118 return DrivetrainInputReader::WheelAndThrottle{
119 wheel, 0.0, 0.0, throttle, 0.0, 0.0, high_gear_};
120}
121
122double UnwrappedAxis(const ::aos::input::driver_station::Data &data,
123 const JoystickAxis &high_bits,
124 const JoystickAxis &low_bits) {
125 const float high_bits_data = data.GetAxis(high_bits);
126 const float low_bits_data = data.GetAxis(low_bits);
127 const int16_t high_bits_data_int =
128 (high_bits_data < 0.0f ? high_bits_data * 128.0f
129 : high_bits_data * 127.0f);
130 const int16_t low_bits_data_int =
131 (low_bits_data < 0.0f ? low_bits_data * 128.0f : low_bits_data * 127.0f);
132
133 const uint16_t high_bits_data_uint =
134 ((static_cast<uint16_t>(high_bits_data_int) & 0xff) + 0x80) & 0xff;
135 const uint16_t low_bits_data_uint =
136 ((static_cast<uint16_t>(low_bits_data_int) & 0xff) + 0x80) & 0xff;
137
138 const uint16_t data_uint = (high_bits_data_uint << 8) | low_bits_data_uint;
139
140 const int32_t data_int = static_cast<int32_t>(data_uint) - 0x8000;
141
142 if (data_int < 0) {
143 return static_cast<double>(data_int) / static_cast<double>(0x8000);
144 } else {
145 return static_cast<double>(data_int) / static_cast<double>(0x7fff);
146 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700147}
148
149DrivetrainInputReader::WheelAndThrottle
150PistolDrivetrainInputReader::GetWheelAndThrottle(
151 const ::aos::input::driver_station::Data &data) {
Austin Schuh2b1fce02018-03-02 20:05:20 -0800152 const double wheel =
153 -UnwrappedAxis(data, wheel_, wheel_low_);
154 const double wheel_velocity =
155 -UnwrappedAxis(data, wheel_velocity_high_, wheel_velocity_low_) * 50.0;
156 const double wheel_torque =
157 -UnwrappedAxis(data, wheel_torque_high_, wheel_torque_low_) / 2.0;
158
Austin Schuh876b4f02018-03-10 19:16:59 -0800159 double throttle =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800160 UnwrappedAxis(data, throttle_, throttle_low_);
161 const double throttle_velocity =
162 UnwrappedAxis(data, throttle_velocity_high_, throttle_velocity_low_) * 50.0;
163 const double throttle_torque =
164 UnwrappedAxis(data, throttle_torque_high_, throttle_torque_low_) / 2.0;
165
Austin Schuh876b4f02018-03-10 19:16:59 -0800166 // TODO(austin): Deal with haptics here.
167 if (throttle < 0) {
168 throttle = ::std::max(-1.0, throttle / 0.7);
169 }
170
Austin Schuh2b1fce02018-03-02 20:05:20 -0800171 if (!data.GetControlBit(ControlBit::kEnabled)) {
172 high_gear_ = default_high_gear_;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700173 }
174
Austin Schuh2b1fce02018-03-02 20:05:20 -0800175 if (data.PosEdge(shift_low_)) {
176 high_gear_ = false;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700177 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700178
Austin Schuh2b1fce02018-03-02 20:05:20 -0800179 if (data.PosEdge(shift_high_)) {
180 high_gear_ = true;
181 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700182
Austin Schuh2b1fce02018-03-02 20:05:20 -0800183 return DrivetrainInputReader::WheelAndThrottle{
184 wheel, wheel_velocity, wheel_torque,
185 throttle, throttle_velocity, throttle_torque,
186 high_gear_};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700187}
188
189DrivetrainInputReader::WheelAndThrottle
190XboxDrivetrainInputReader::GetWheelAndThrottle(
191 const ::aos::input::driver_station::Data &data) {
192 // xbox
193 constexpr double kWheelDeadband = 0.05;
194 constexpr double kThrottleDeadband = 0.05;
195 const double wheel =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800196 aos::Deadband(-data.GetAxis(wheel_), kWheelDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700197
198 const double unmodified_throttle =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800199 aos::Deadband(-data.GetAxis(throttle_), kThrottleDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700200
201 // Apply a sin function that's scaled to make it feel better.
202 constexpr double throttle_range = M_PI_2 * 0.9;
203
204 double throttle = ::std::sin(throttle_range * unmodified_throttle) /
205 ::std::sin(throttle_range);
206 throttle = ::std::sin(throttle_range * throttle) / ::std::sin(throttle_range);
207 throttle = 2.0 * unmodified_throttle - throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -0800208 return DrivetrainInputReader::WheelAndThrottle{wheel, 0.0, 0.0, throttle,
209 0.0, 0.0, true};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700210}
211
212std::unique_ptr<SteeringWheelDrivetrainInputReader>
Sabina Davis82b19182017-11-10 09:30:25 -0800213SteeringWheelDrivetrainInputReader::Make(bool default_high_gear) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700214 const JoystickAxis kSteeringWheel(1, 1), kDriveThrottle(2, 2);
215 const ButtonLocation kQuickTurn(1, 5);
216 const ButtonLocation kTurn1(1, 7);
217 const ButtonLocation kTurn2(1, 11);
218 std::unique_ptr<SteeringWheelDrivetrainInputReader> result(
James Kuszmaul8bad2412019-03-10 10:47:56 -0700219 new SteeringWheelDrivetrainInputReader(
220 kSteeringWheel, kDriveThrottle, kQuickTurn, kTurn1,
221 TurnButtonUse::kControlLoopDriving, kTurn2,
222 TurnButtonUse::kControlLoopDriving));
Sabina Davis82b19182017-11-10 09:30:25 -0800223 result.get()->set_default_high_gear(default_high_gear);
224
Sabina Davis92d2efa2017-11-04 22:35:25 -0700225 return result;
226}
227
Austin Schuh2b1fce02018-03-02 20:05:20 -0800228std::unique_ptr<PistolDrivetrainInputReader> PistolDrivetrainInputReader::Make(
James Kuszmaul8bad2412019-03-10 10:47:56 -0700229 bool default_high_gear, TopButtonUse top_button_use) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700230 // Pistol Grip controller
Austin Schuh2b1fce02018-03-02 20:05:20 -0800231 const JoystickAxis kTriggerHigh(1, 1), kTriggerLow(1, 4),
232 kTriggerVelocityHigh(1, 2), kTriggerVelocityLow(1, 5),
233 kTriggerTorqueHigh(1, 3), kTriggerTorqueLow(1, 6);
234
235 const JoystickAxis kWheelHigh(2, 1), kWheelLow(2, 4),
236 kWheelVelocityHigh(2, 2), kWheelVelocityLow(2, 5), kWheelTorqueHigh(2, 3),
237 kWheelTorqueLow(2, 6);
238
Austin Schuhe8a54c02018-03-05 00:25:58 -0800239 const ButtonLocation kQuickTurn(1, 3);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700240
James Kuszmaul8bad2412019-03-10 10:47:56 -0700241 const ButtonLocation TopButton(1, 1);
242 const ButtonLocation SecondButton(1, 2);
243 // Non-existant button for nops.
244 const ButtonLocation DummyButton(1, 10);
245
246 // TODO(james): Make a copy assignment operator for ButtonLocation so we don't
247 // have to shoehorn in these ternary operators.
Austin Schuh48d3a962019-03-17 18:12:32 -0700248 const ButtonLocation kTurn1 = (top_button_use == TopButtonUse::kLineFollow)
249 ? SecondButton
250 : DummyButton;
251 // Turn2 does closed loop driving.
252 const ButtonLocation kTurn2 =
James Kuszmaul8bad2412019-03-10 10:47:56 -0700253 (top_button_use == TopButtonUse::kLineFollow) ? TopButton : DummyButton;
Austin Schuh48d3a962019-03-17 18:12:32 -0700254
James Kuszmaul8bad2412019-03-10 10:47:56 -0700255 const ButtonLocation kShiftHigh =
256 (top_button_use == TopButtonUse::kShift) ? TopButton : DummyButton;
257 const ButtonLocation kShiftLow =
258 (top_button_use == TopButtonUse::kShift) ? SecondButton : DummyButton;
259
Sabina Davis92d2efa2017-11-04 22:35:25 -0700260 std::unique_ptr<PistolDrivetrainInputReader> result(
Austin Schuh2b1fce02018-03-02 20:05:20 -0800261 new PistolDrivetrainInputReader(
262 kWheelHigh, kWheelLow, kTriggerVelocityHigh, kTriggerVelocityLow,
263 kTriggerTorqueHigh, kTriggerTorqueLow, kTriggerHigh, kTriggerLow,
264 kWheelVelocityHigh, kWheelVelocityLow, kWheelTorqueHigh,
265 kWheelTorqueLow, kQuickTurn, kShiftHigh, kShiftLow, kTurn1, kTurn2));
266
267 result->set_default_high_gear(default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700268 return result;
269}
270
271std::unique_ptr<XboxDrivetrainInputReader> XboxDrivetrainInputReader::Make() {
272 // xbox
273 const JoystickAxis kSteeringWheel(1, 5), kDriveThrottle(1, 2);
274 const ButtonLocation kQuickTurn(1, 5);
275
276 // Nop
277 const ButtonLocation kTurn1(1, 1);
278 const ButtonLocation kTurn2(1, 2);
279
280 std::unique_ptr<XboxDrivetrainInputReader> result(
281 new XboxDrivetrainInputReader(kSteeringWheel, kDriveThrottle, kQuickTurn,
James Kuszmaul8bad2412019-03-10 10:47:56 -0700282 kTurn1, TurnButtonUse::kControlLoopDriving,
283 kTurn2,
284 TurnButtonUse::kControlLoopDriving));
Sabina Davis92d2efa2017-11-04 22:35:25 -0700285 return result;
286}
287::std::unique_ptr<DrivetrainInputReader> DrivetrainInputReader::Make(
Sabina Davis82b19182017-11-10 09:30:25 -0800288 InputType type,
Austin Schuhbcce26a2018-03-26 23:41:24 -0700289 const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
290 &dt_config) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700291 std::unique_ptr<DrivetrainInputReader> drivetrain_input_reader;
292
293 using InputType = DrivetrainInputReader::InputType;
Sabina Davis82b19182017-11-10 09:30:25 -0800294
Sabina Davis92d2efa2017-11-04 22:35:25 -0700295 switch (type) {
296 case InputType::kSteeringWheel:
Sabina Davis82b19182017-11-10 09:30:25 -0800297 drivetrain_input_reader =
298 SteeringWheelDrivetrainInputReader::Make(dt_config.default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700299 break;
300 case InputType::kPistol:
James Kuszmaul8bad2412019-03-10 10:47:56 -0700301 drivetrain_input_reader = PistolDrivetrainInputReader::Make(
302 dt_config.default_high_gear,
303 dt_config.pistol_grip_shift_enables_line_follow
304 ? PistolDrivetrainInputReader::TopButtonUse::kLineFollow
305 : PistolDrivetrainInputReader::TopButtonUse::kShift);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700306 break;
307 case InputType::kXbox:
308 drivetrain_input_reader = XboxDrivetrainInputReader::Make();
309 break;
310 }
311 return drivetrain_input_reader;
312}
313
314} // namespace input
315} // namespace aos