blob: 02957a839d11ab090fe42d09338d74d3019a0034 [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
65 if (is_control_loop_driving) {
Sabina Davis92d2efa2017-11-04 22:35:25 -070066 if (drivetrain_queue.status.get()) {
67 left_goal_ = drivetrain_queue.status->estimated_left_position;
68 right_goal_ = drivetrain_queue.status->estimated_right_position;
69 }
70 }
71 const double current_left_goal =
72 left_goal_ - wheel * wheel_multiplier_ + throttle * 0.3;
73 const double current_right_goal =
74 right_goal_ + wheel * wheel_multiplier_ + throttle * 0.3;
Sabina Davis92d2efa2017-11-04 22:35:25 -070075 auto new_drivetrain_goal = drivetrain_queue.goal.MakeMessage();
Austin Schuh2b1fce02018-03-02 20:05:20 -080076 new_drivetrain_goal->wheel = wheel;
77 new_drivetrain_goal->wheel_velocity = wheel_velocity;
78 new_drivetrain_goal->wheel_torque = wheel_torque;
Sabina Davis92d2efa2017-11-04 22:35:25 -070079 new_drivetrain_goal->throttle = throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -080080 new_drivetrain_goal->throttle_velocity = throttle_velocity;
81 new_drivetrain_goal->throttle_torque = throttle_torque;
Sabina Davis82b19182017-11-10 09:30:25 -080082 new_drivetrain_goal->highgear = high_gear;
83 new_drivetrain_goal->quickturn = data.IsPressed(quick_turn_);
James Kuszmaul8bad2412019-03-10 10:47:56 -070084 new_drivetrain_goal->controller_type =
85 is_line_following ? 3 : (is_control_loop_driving ? 1 : 0);
Sabina Davis92d2efa2017-11-04 22:35:25 -070086 new_drivetrain_goal->left_goal = current_left_goal;
87 new_drivetrain_goal->right_goal = current_right_goal;
Sabina Davis92d2efa2017-11-04 22:35:25 -070088
89 new_drivetrain_goal->linear.max_velocity = 3.0;
90 new_drivetrain_goal->linear.max_acceleration = 20.0;
91
92 if (!new_drivetrain_goal.Send()) {
93 LOG(WARNING, "sending stick values failed\n");
94 }
95}
96
97DrivetrainInputReader::WheelAndThrottle
98SteeringWheelDrivetrainInputReader::GetWheelAndThrottle(
99 const ::aos::input::driver_station::Data &data) {
Austin Schuh2b1fce02018-03-02 20:05:20 -0800100 const double wheel = -data.GetAxis(wheel_);
101 const double throttle = -data.GetAxis(throttle_);
Sabina Davis82b19182017-11-10 09:30:25 -0800102
103 if (!data.GetControlBit(ControlBit::kEnabled)) {
104 high_gear_ = default_high_gear_;
105 }
106
107 if (data.PosEdge(kShiftLow)) {
108 high_gear_ = false;
109 }
110
111 if (data.PosEdge(kShiftHigh) || data.PosEdge(kShiftHigh2)) {
112 high_gear_ = true;
113 }
114
Austin Schuh2b1fce02018-03-02 20:05:20 -0800115 return DrivetrainInputReader::WheelAndThrottle{
116 wheel, 0.0, 0.0, throttle, 0.0, 0.0, high_gear_};
117}
118
119double UnwrappedAxis(const ::aos::input::driver_station::Data &data,
120 const JoystickAxis &high_bits,
121 const JoystickAxis &low_bits) {
122 const float high_bits_data = data.GetAxis(high_bits);
123 const float low_bits_data = data.GetAxis(low_bits);
124 const int16_t high_bits_data_int =
125 (high_bits_data < 0.0f ? high_bits_data * 128.0f
126 : high_bits_data * 127.0f);
127 const int16_t low_bits_data_int =
128 (low_bits_data < 0.0f ? low_bits_data * 128.0f : low_bits_data * 127.0f);
129
130 const uint16_t high_bits_data_uint =
131 ((static_cast<uint16_t>(high_bits_data_int) & 0xff) + 0x80) & 0xff;
132 const uint16_t low_bits_data_uint =
133 ((static_cast<uint16_t>(low_bits_data_int) & 0xff) + 0x80) & 0xff;
134
135 const uint16_t data_uint = (high_bits_data_uint << 8) | low_bits_data_uint;
136
137 const int32_t data_int = static_cast<int32_t>(data_uint) - 0x8000;
138
139 if (data_int < 0) {
140 return static_cast<double>(data_int) / static_cast<double>(0x8000);
141 } else {
142 return static_cast<double>(data_int) / static_cast<double>(0x7fff);
143 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700144}
145
146DrivetrainInputReader::WheelAndThrottle
147PistolDrivetrainInputReader::GetWheelAndThrottle(
148 const ::aos::input::driver_station::Data &data) {
Austin Schuh2b1fce02018-03-02 20:05:20 -0800149 const double wheel =
150 -UnwrappedAxis(data, wheel_, wheel_low_);
151 const double wheel_velocity =
152 -UnwrappedAxis(data, wheel_velocity_high_, wheel_velocity_low_) * 50.0;
153 const double wheel_torque =
154 -UnwrappedAxis(data, wheel_torque_high_, wheel_torque_low_) / 2.0;
155
Austin Schuh876b4f02018-03-10 19:16:59 -0800156 double throttle =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800157 UnwrappedAxis(data, throttle_, throttle_low_);
158 const double throttle_velocity =
159 UnwrappedAxis(data, throttle_velocity_high_, throttle_velocity_low_) * 50.0;
160 const double throttle_torque =
161 UnwrappedAxis(data, throttle_torque_high_, throttle_torque_low_) / 2.0;
162
Austin Schuh876b4f02018-03-10 19:16:59 -0800163 // TODO(austin): Deal with haptics here.
164 if (throttle < 0) {
165 throttle = ::std::max(-1.0, throttle / 0.7);
166 }
167
Austin Schuh2b1fce02018-03-02 20:05:20 -0800168 if (!data.GetControlBit(ControlBit::kEnabled)) {
169 high_gear_ = default_high_gear_;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700170 }
171
Austin Schuh2b1fce02018-03-02 20:05:20 -0800172 if (data.PosEdge(shift_low_)) {
173 high_gear_ = false;
Sabina Davis92d2efa2017-11-04 22:35:25 -0700174 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700175
Austin Schuh2b1fce02018-03-02 20:05:20 -0800176 if (data.PosEdge(shift_high_)) {
177 high_gear_ = true;
178 }
Sabina Davis92d2efa2017-11-04 22:35:25 -0700179
Austin Schuh2b1fce02018-03-02 20:05:20 -0800180 return DrivetrainInputReader::WheelAndThrottle{
181 wheel, wheel_velocity, wheel_torque,
182 throttle, throttle_velocity, throttle_torque,
183 high_gear_};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700184}
185
186DrivetrainInputReader::WheelAndThrottle
187XboxDrivetrainInputReader::GetWheelAndThrottle(
188 const ::aos::input::driver_station::Data &data) {
189 // xbox
190 constexpr double kWheelDeadband = 0.05;
191 constexpr double kThrottleDeadband = 0.05;
192 const double wheel =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800193 aos::Deadband(-data.GetAxis(wheel_), kWheelDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700194
195 const double unmodified_throttle =
Austin Schuh2b1fce02018-03-02 20:05:20 -0800196 aos::Deadband(-data.GetAxis(throttle_), kThrottleDeadband, 1.0);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700197
198 // Apply a sin function that's scaled to make it feel better.
199 constexpr double throttle_range = M_PI_2 * 0.9;
200
201 double throttle = ::std::sin(throttle_range * unmodified_throttle) /
202 ::std::sin(throttle_range);
203 throttle = ::std::sin(throttle_range * throttle) / ::std::sin(throttle_range);
204 throttle = 2.0 * unmodified_throttle - throttle;
Austin Schuh2b1fce02018-03-02 20:05:20 -0800205 return DrivetrainInputReader::WheelAndThrottle{wheel, 0.0, 0.0, throttle,
206 0.0, 0.0, true};
Sabina Davis92d2efa2017-11-04 22:35:25 -0700207}
208
209std::unique_ptr<SteeringWheelDrivetrainInputReader>
Sabina Davis82b19182017-11-10 09:30:25 -0800210SteeringWheelDrivetrainInputReader::Make(bool default_high_gear) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700211 const JoystickAxis kSteeringWheel(1, 1), kDriveThrottle(2, 2);
212 const ButtonLocation kQuickTurn(1, 5);
213 const ButtonLocation kTurn1(1, 7);
214 const ButtonLocation kTurn2(1, 11);
215 std::unique_ptr<SteeringWheelDrivetrainInputReader> result(
James Kuszmaul8bad2412019-03-10 10:47:56 -0700216 new SteeringWheelDrivetrainInputReader(
217 kSteeringWheel, kDriveThrottle, kQuickTurn, kTurn1,
218 TurnButtonUse::kControlLoopDriving, kTurn2,
219 TurnButtonUse::kControlLoopDriving));
Sabina Davis82b19182017-11-10 09:30:25 -0800220 result.get()->set_default_high_gear(default_high_gear);
221
Sabina Davis92d2efa2017-11-04 22:35:25 -0700222 return result;
223}
224
Austin Schuh2b1fce02018-03-02 20:05:20 -0800225std::unique_ptr<PistolDrivetrainInputReader> PistolDrivetrainInputReader::Make(
James Kuszmaul8bad2412019-03-10 10:47:56 -0700226 bool default_high_gear, TopButtonUse top_button_use) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700227 // Pistol Grip controller
Austin Schuh2b1fce02018-03-02 20:05:20 -0800228 const JoystickAxis kTriggerHigh(1, 1), kTriggerLow(1, 4),
229 kTriggerVelocityHigh(1, 2), kTriggerVelocityLow(1, 5),
230 kTriggerTorqueHigh(1, 3), kTriggerTorqueLow(1, 6);
231
232 const JoystickAxis kWheelHigh(2, 1), kWheelLow(2, 4),
233 kWheelVelocityHigh(2, 2), kWheelVelocityLow(2, 5), kWheelTorqueHigh(2, 3),
234 kWheelTorqueLow(2, 6);
235
Austin Schuhe8a54c02018-03-05 00:25:58 -0800236 const ButtonLocation kQuickTurn(1, 3);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700237
James Kuszmaul8bad2412019-03-10 10:47:56 -0700238 const ButtonLocation TopButton(1, 1);
239 const ButtonLocation SecondButton(1, 2);
240 // Non-existant button for nops.
241 const ButtonLocation DummyButton(1, 10);
242
243 // TODO(james): Make a copy assignment operator for ButtonLocation so we don't
244 // have to shoehorn in these ternary operators.
245 const ButtonLocation kTurn1 =
246 (top_button_use == TopButtonUse::kLineFollow) ? TopButton : DummyButton;
247 // Turn2 currently does nothing on the pistol grip, ever.
248 const ButtonLocation kTurn2 = DummyButton;
249 const ButtonLocation kShiftHigh =
250 (top_button_use == TopButtonUse::kShift) ? TopButton : DummyButton;
251 const ButtonLocation kShiftLow =
252 (top_button_use == TopButtonUse::kShift) ? SecondButton : DummyButton;
253
Sabina Davis92d2efa2017-11-04 22:35:25 -0700254 std::unique_ptr<PistolDrivetrainInputReader> result(
Austin Schuh2b1fce02018-03-02 20:05:20 -0800255 new PistolDrivetrainInputReader(
256 kWheelHigh, kWheelLow, kTriggerVelocityHigh, kTriggerVelocityLow,
257 kTriggerTorqueHigh, kTriggerTorqueLow, kTriggerHigh, kTriggerLow,
258 kWheelVelocityHigh, kWheelVelocityLow, kWheelTorqueHigh,
259 kWheelTorqueLow, kQuickTurn, kShiftHigh, kShiftLow, kTurn1, kTurn2));
260
261 result->set_default_high_gear(default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700262 return result;
263}
264
265std::unique_ptr<XboxDrivetrainInputReader> XboxDrivetrainInputReader::Make() {
266 // xbox
267 const JoystickAxis kSteeringWheel(1, 5), kDriveThrottle(1, 2);
268 const ButtonLocation kQuickTurn(1, 5);
269
270 // Nop
271 const ButtonLocation kTurn1(1, 1);
272 const ButtonLocation kTurn2(1, 2);
273
274 std::unique_ptr<XboxDrivetrainInputReader> result(
275 new XboxDrivetrainInputReader(kSteeringWheel, kDriveThrottle, kQuickTurn,
James Kuszmaul8bad2412019-03-10 10:47:56 -0700276 kTurn1, TurnButtonUse::kControlLoopDriving,
277 kTurn2,
278 TurnButtonUse::kControlLoopDriving));
Sabina Davis92d2efa2017-11-04 22:35:25 -0700279 return result;
280}
281::std::unique_ptr<DrivetrainInputReader> DrivetrainInputReader::Make(
Sabina Davis82b19182017-11-10 09:30:25 -0800282 InputType type,
Austin Schuhbcce26a2018-03-26 23:41:24 -0700283 const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
284 &dt_config) {
Sabina Davis92d2efa2017-11-04 22:35:25 -0700285 std::unique_ptr<DrivetrainInputReader> drivetrain_input_reader;
286
287 using InputType = DrivetrainInputReader::InputType;
Sabina Davis82b19182017-11-10 09:30:25 -0800288
Sabina Davis92d2efa2017-11-04 22:35:25 -0700289 switch (type) {
290 case InputType::kSteeringWheel:
Sabina Davis82b19182017-11-10 09:30:25 -0800291 drivetrain_input_reader =
292 SteeringWheelDrivetrainInputReader::Make(dt_config.default_high_gear);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700293 break;
294 case InputType::kPistol:
James Kuszmaul8bad2412019-03-10 10:47:56 -0700295 drivetrain_input_reader = PistolDrivetrainInputReader::Make(
296 dt_config.default_high_gear,
297 dt_config.pistol_grip_shift_enables_line_follow
298 ? PistolDrivetrainInputReader::TopButtonUse::kLineFollow
299 : PistolDrivetrainInputReader::TopButtonUse::kShift);
Sabina Davis92d2efa2017-11-04 22:35:25 -0700300 break;
301 case InputType::kXbox:
302 drivetrain_input_reader = XboxDrivetrainInputReader::Make();
303 break;
304 }
305 return drivetrain_input_reader;
306}
307
308} // namespace input
309} // namespace aos