RSeries astromech firmware
TankDrive.h
Go to the documentation of this file.
1 #ifndef TankDrive_h
2 #define TankDrive_h
3 
4 #include "ReelTwo.h"
5 #include "core/AnimatedEvent.h"
6 #include "core/SetupEvent.h"
7 #include "JoystickController.h"
8 #include "TargetSteering.h"
9 
10 #ifdef USE_MOTOR_DEBUG
11 #define MOTOR_DEBUG_PRINT(s) DEBUG_PRINT(s)
12 #define MOTOR_DEBUG_PRINTLN(s) DEBUG_PRINTLN(s)
13 #define MOTOR_DEBUG_PRINT_HEX(s) DEBUG_PRINT_HEX(s)
14 #define MOTOR_DEBUG_PRINTLN_HEX(s) DEBUG_PRINTLN_HEX(s)
15 #else
16 #define MOTOR_DEBUG_PRINT(s)
17 #define MOTOR_DEBUG_PRINTLN(s)
18 #define MOTOR_DEBUG_PRINT_HEX(s)
19 #define MOTOR_DEBUG_PRINTLN_HEX(s)
20 #endif
21 
37 class TankDrive : public SetupEvent, public AnimatedEvent
38 {
39 public:
48  {
49  // Default enabled
50  setEnable(true);
51  // Default to half speed max
52  setMaxSpeed(0.5);
53  // Default 25ms
54  setSerialLatency(25);
55  setScaling(true);
60  setChannelMixing(true);
61  setThrottleInverted(false);
62  setTurnInverted(false);
64  setUseThrottle(true);
65  setUseHardStop(true);
66  }
67 
68  virtual void setup() override
69  {
70  }
71 
72  bool getEnable()
73  {
74  return fEnabled;
75  }
76 
77  void setEnable(bool enable)
78  {
79  fEnabled = enable;
80  }
81 
82  uint32_t getSerialLatency()
83  {
84  return fSerialLatency;
85  }
86 
87  void setSerialLatency(uint32_t ms)
88  {
89  fSerialLatency = ms;
90  }
91 
93  {
94  return fChannelMixing;
95  }
96 
97  void setChannelMixing(bool mixing)
98  {
99  fChannelMixing = mixing;
100  }
101 
103  {
104  return fThrottleInverted;
105  }
106 
107  void setThrottleInverted(bool invert)
108  {
109  fThrottleInverted = invert;
110  }
111 
113  {
114  return fTurnInverted;
115  }
116 
117  void setTurnInverted(bool invert)
118  {
119  fTurnInverted = invert;
120  }
121 
122  bool getScaling()
123  {
124  return fScaling;
125  }
126 
127  void setScaling(bool scaling)
128  {
129  fScaling = scaling;
130  }
131 
132  float getMaxSpeed()
133  {
134  return fSpeedModifier;
135  }
136 
137  void setMaxSpeed(float modifier)
138  {
139  stop();
140  fSpeedModifier = min(max(modifier, 0.0f), 1.0f);
142  }
143 
145  {
147  }
148 
149  void setThrottleAccelerationScale(unsigned scale)
150  {
152  }
153 
155  {
157  }
158 
159  void setThrottleDecelerationScale(unsigned scale)
160  {
162  }
163 
165  {
166  return fTurnAccelerationScale;
167  }
168 
169  void setTurnAccelerationScale(unsigned scale)
170  {
171  fTurnAccelerationScale = scale;
172  }
173 
175  {
176  return fTurnDecelerationScale;
177  }
178 
179  void setTurnDecelerationScale(unsigned scale)
180  {
181  fTurnDecelerationScale = scale;
182  }
183 
184  void setAccelerationScale(unsigned scale)
185  {
188  }
189 
190  void setDecelerationScale(unsigned scale)
191  {
194  }
195 
197  {
199  }
200 
202  {
203  fGuestStick = &guestStick;
204  }
205 
207  {
208  return fGuestSpeedModifier;
209  }
210 
211  void setGuestSpeedModifier(float maxGuestSpeed)
212  {
213  fGuestSpeedModifier = min(max(maxGuestSpeed, 0.0f), 1.0f);
214  }
215 
217  {
218  fTargetSteering = target;
219  }
220 
221  bool useThrottle()
222  {
223  return fUseThrottle;
224  }
225 
226  bool useHardStop()
227  {
228  return fUseHardStop;
229  }
230 
232  {
233  return fUseLeftStick;
234  }
235 
237  {
238  return !fUseLeftStick;
239  }
240 
241  void setUseThrottle(bool use)
242  {
243  fUseThrottle = use;
244  }
245 
246  void setUseHardStop(bool use)
247  {
248  fUseHardStop = use;
249  }
250 
252  {
253  fUseLeftStick = true;
254  }
255 
257  {
258  fUseLeftStick = false;
259  }
260 
261  virtual void stop()
262  {
263  fMotorsStopped = true;
264  fDriveThrottle = 0;
265  fDriveTurning = 0;
266  }
267 
269  {
270  if (fDriveStick.isConnected())
271  {
272  return &fDriveStick;
273  }
274  else if (fGuestStick != nullptr && fGuestStick->isConnected())
275  {
276  return fGuestStick;
277  }
278  return nullptr;
279  }
280 
284  virtual void animate() override
285  {
286  if (fDriveStick.isConnected())
287  {
289  }
290  else if (fGuestStick != nullptr && fGuestStick->isConnected())
291  {
293  }
294  else if (fWasConnected)
295  {
296  stop();
297  MOTOR_DEBUG_PRINTLN("Waiting to reconnect");
298  fWasConnected = false;
299  }
300  }
301 
302 protected:
303  virtual void motor(float left, float right, float throttle) = 0;
304 
305  virtual float getThrottle()
306  {
308  {
309  if (useLeftStick())
310  return float(fDriveStick.state.analog.button.l2)/255.0f;
311  if (useRightStick())
312  return float(fDriveStick.state.analog.button.r2)/255.0f;
313  }
314  return 0.0f;
315  }
316 
317  virtual bool hasThrottle()
318  {
319  return false;
320  }
321 
322  virtual float throttleSpeed(float speedModifier)
323  {
324  if (useThrottle())
325  {
326  if (!hasThrottle())
327  {
328  // We are going to simulate the throttle by increasing the speed modifier
329  if (fDriveStick.isConnected())
330  {
331  speedModifier += getThrottle() * ((1.0f-speedModifier));
332  }
333  return min(max(speedModifier,0.0f),1.0f) * -1.0f;
334  }
335  else
336  {
337  if (fDriveStick.isConnected())
338  {
339  speedModifier = getThrottle();
340  }
341  }
342  }
343  return speedModifier;
344  }
345 
346  void driveStick(JoystickController* stick, float speedModifier)
347  {
348  fWasConnected = true;
349  if (!fEnabled)
350  {
351  stop();
352  }
353  else if (useHardStop() &&
354  ((useLeftStick() && stick->state.button.l1) ||
355  (useRightStick() && stick->state.button.r1)))
356  {
357  if (!fMotorsStopped)
358  {
359  MOTOR_DEBUG_PRINTLN("STOP");
360  stop();
361  }
362  /* Disable Target Steering */
363  setTargetSteering(nullptr);
364  }
365  else
366  {
367  if (millis() - fLastCommand > fSerialLatency)
368  {
369  auto stickx = useLeftStick() ? stick->state.analog.stick.lx : stick->state.analog.stick.rx;
370  auto sticky = useLeftStick() ? stick->state.analog.stick.ly : stick->state.analog.stick.ry;
371  // float drive_mod = speedModifier * -1.0f;
372  auto drive_mod = throttleSpeed(speedModifier);
373  auto turning = (float)(stickx + 128) / 127.5f - 1.0f;
374  auto throttle = (float)(sticky + 128) / 127.5f - 1.0f;
375  if (fThrottleInverted)
376  throttle = -throttle;
377  if (fTurnInverted)
378  turning = -turning;
379 
380  if (abs(turning) < 0.2)
381  turning = 0;
382  else
383  turning = pow(abs(turning)-0.2, 1.4) * ((turning < 0) ? -1 : 1);
384  if (abs(throttle) < 0.2)
385  throttle = 0;
386 
387  if (fTargetSteering)
388  {
389  auto targetThrottle = fTargetSteering->getThrottle();
390  auto targetTurning = fTargetSteering->getTurning();
391  throttle = (throttle != 0) ? throttle : targetThrottle;
392  turning = (turning != 0) ? turning : targetTurning;
393  }
394 
395  // clamp turning if throttle is greater than turning
396  // theory being that if you are at top speed turning should
397  // be less responsive. if you are full on turning throttle
398  // should remain responsive.
399  // if (abs(turning) <= abs(fDriveThrottle))
400  // {
401  // if (abs(fDriveThrottle) >= 0.8)
402  // turning /= 8;
403  // else if (abs(fDriveThrottle) >= 0.6)
404  // turning /= 6;
405  // else if (abs(fDriveThrottle) >= 0.4)
406  // turning /= 4;
407  // else if (abs(fDriveThrottle) >= 0.2)
408  // turning /= 2;
409  // }
410  if (turning != 0 || throttle != 0)
411  {
412  MOTOR_DEBUG_PRINT("TURNING "); MOTOR_DEBUG_PRINT(turning);
413  MOTOR_DEBUG_PRINT(" THROTTLE "); MOTOR_DEBUG_PRINTLN(throttle);
414  }
415  if (fScaling)
416  {
417  if (throttle > fDriveThrottle)
418  {
419  float scale = fThrottleAccelerationScale;
420  if (fDriveThrottle < 0)
421  {
422  MOTOR_DEBUG_PRINT("DECELERATING ");
424  }
425  else
426  {
427  MOTOR_DEBUG_PRINT("ACCELERATING REVERSE ");
428  }
429  float val = max(abs(throttle - fDriveThrottle) / scale, 0.01f);
430  MOTOR_DEBUG_PRINT(val);
431  MOTOR_DEBUG_PRINT(" throttle: ");
432  MOTOR_DEBUG_PRINT(throttle);
433  MOTOR_DEBUG_PRINT(" drive : ");
435  MOTOR_DEBUG_PRINT(" => ");
436  fDriveThrottle = ((int)round(min(fDriveThrottle + val, throttle)*100))/100.0f;
438  }
439  else if (throttle < fDriveThrottle)
440  {
441  float scale = fThrottleAccelerationScale;
442  if (fDriveThrottle > 0)
443  {
444  MOTOR_DEBUG_PRINT("DECELERATING REVERSE ");
446  }
447  else
448  {
449  MOTOR_DEBUG_PRINT("ACCELERATING ");
450  }
451  float val = abs(throttle - fDriveThrottle) / scale;
452  MOTOR_DEBUG_PRINT(val);
453  MOTOR_DEBUG_PRINT(" throttle: ");
454  MOTOR_DEBUG_PRINT(throttle);
455  MOTOR_DEBUG_PRINT(" drive : ");
457  MOTOR_DEBUG_PRINT(" => ");
458  fDriveThrottle = ((int)floor(max(fDriveThrottle - val, throttle)*100))/100.0f;
460  }
461  // Scale turning by fDriveThrottle
462  turning *= (1.0f - abs(fDriveThrottle) * 0.1);
463  if (turning > fDriveTurning)
464  {
465  float scale = fTurnAccelerationScale;
466  if (fDriveTurning < 0)
467  {
468  MOTOR_DEBUG_PRINT("DECELERATING LEFT ");
469  scale = fTurnDecelerationScale;
470  }
471  else
472  {
473  MOTOR_DEBUG_PRINT("ACCELERATING RIGHT ");
474  }
475  float val = max(abs(turning - fDriveTurning) / scale, 0.01f);
476  MOTOR_DEBUG_PRINT(val);
477  MOTOR_DEBUG_PRINT(" turning: ");
478  MOTOR_DEBUG_PRINT(turning);
479  MOTOR_DEBUG_PRINT(" drive : ");
481  MOTOR_DEBUG_PRINT(" => ");
482  fDriveTurning = ((int)round(min(fDriveTurning + val, turning)*100))/100.0f;
484  MOTOR_DEBUG_PRINT(" ");
485  }
486  else if (turning < fDriveTurning)
487  {
488  float scale = fTurnAccelerationScale;
489  if (fDriveTurning > 0)
490  {
491  MOTOR_DEBUG_PRINT("DECELERATING RIGHT ");
492  scale = fTurnDecelerationScale;
493  }
494  else
495  {
496  MOTOR_DEBUG_PRINT("ACCELERATING LEFT ");
497  }
498  float val = abs(turning - fDriveTurning) / scale;
499  MOTOR_DEBUG_PRINT(val);
500  MOTOR_DEBUG_PRINT(" turning: ");
501  MOTOR_DEBUG_PRINT(turning);
502  MOTOR_DEBUG_PRINT(" drive : ");
504  MOTOR_DEBUG_PRINT(" => ");
505  fDriveTurning = ((int)floor(max(fDriveTurning - val, turning)*100))/100.0f;
507  }
508  }
509  else
510  {
511  fDriveThrottle = throttle;
512  fDriveTurning = turning;
513  }
514 
515  auto x = fDriveThrottle;
516  auto y = fDriveTurning;
517 
518  auto target_left = x;
519  auto target_right = y;
520  if (fChannelMixing)
521  {
522  auto r = hypot(x, y);
523  auto t = atan2(y, x);
524  // rotate 45 degrees
525  t += M_PI / 4;
526 
527  target_left = r * cos(t);
528  target_right = r * sin(t);
529 
530  // rescale the new coords
531  target_left *= sqrt(2);
532  target_right *= sqrt(2);
533  }
534  // clamp to -1/+1 and apply max speed limit
535  target_left = max(-1.0f, min(target_left, 1.0f));
536  target_right = max(-1.0f, min(target_right, 1.0f));
537 
538  motor(target_left, target_right, drive_mod);
539  fLastCommand = millis();
540  fMotorsStopped = false;
541  }
542  }
543  }
544 
545 protected:
549  bool fEnabled = false;
550  bool fWasConnected = false;
551  bool fMotorsStopped = false;
552  bool fChannelMixing = false;
553  bool fScaling = false;
554  bool fUseLeftStick = true;
555  bool fUseThrottle = true;
556  bool fUseHardStop = true;
557  bool fThrottleInverted = false;
558  bool fTurnInverted = false;
559  float fSpeedModifier = 0;
561  uint32_t fSerialLatency = 0;
562  uint32_t fLastCommand = 0;
567  float fDriveThrottle = 0;
568  float fDriveTurning = 0;
569 };
570 #endif
TankDrive::useHardStop
bool useHardStop()
Definition: TankDrive.h:226
TankDrive::animate
virtual void animate() override
Dispatch any received i2c event to CommandEvent.
Definition: TankDrive.h:284
TankDrive::getMaxSpeed
float getMaxSpeed()
Definition: TankDrive.h:132
JoystickController::state
State state
Definition: JoystickController.h:136
TankDrive::getTurnInverted
bool getTurnInverted()
Definition: TankDrive.h:112
JoystickController::AnalogButton::l2
uint8_t l2
Definition: JoystickController.h:22
TankDrive::setUseRightStick
void setUseRightStick()
Definition: TankDrive.h:256
TankDrive::fGuestSpeedModifier
float fGuestSpeedModifier
Definition: TankDrive.h:560
TankDrive::fDriveThrottle
float fDriveThrottle
Definition: TankDrive.h:567
TankDrive::fDriveTurning
float fDriveTurning
Definition: TankDrive.h:568
TankDrive::fSpeedModifier
float fSpeedModifier
Definition: TankDrive.h:559
TankDrive::fEnabled
bool fEnabled
Definition: TankDrive.h:549
TankDrive::hasThrottle
virtual bool hasThrottle()
Definition: TankDrive.h:317
TankDrive::setGuestStick
void setGuestStick(JoystickController &guestStick)
Definition: TankDrive.h:201
JoystickController::AnalogStick::lx
int8_t lx
Definition: JoystickController.h:9
ReelTwo.h
SetupEvent.h
TankDrive::getSerialLatency
uint32_t getSerialLatency()
Definition: TankDrive.h:82
AnimatedEvent
Base class for all animated devices. AnimatedEvent::animate() is called for each device once through ...
Definition: AnimatedEvent.h:18
TankDrive::fTurnInverted
bool fTurnInverted
Definition: TankDrive.h:558
TankDrive::fDriveStick
JoystickController & fDriveStick
Definition: TankDrive.h:546
SetupEvent
Base class for all devices that require setup that cannot happen in the constructor....
Definition: SetupEvent.h:15
TankDrive::fThrottleDecelerationScale
unsigned fThrottleDecelerationScale
Definition: TankDrive.h:564
TankDrive::getThrottleAccelerationScale
unsigned getThrottleAccelerationScale()
Definition: TankDrive.h:144
JoystickController::isConnected
bool isConnected() const
Definition: JoystickController.h:146
AnimatedEvent.h
TankDrive::setEnable
void setEnable(bool enable)
Definition: TankDrive.h:77
TankDrive::getThrottleInverted
bool getThrottleInverted()
Definition: TankDrive.h:102
TankDrive::useRightStick
bool useRightStick()
Definition: TankDrive.h:236
TankDrive::fThrottleAccelerationScale
unsigned fThrottleAccelerationScale
Definition: TankDrive.h:563
TankDrive::setThrottleInverted
void setThrottleInverted(bool invert)
Definition: TankDrive.h:107
TankDrive::fUseLeftStick
bool fUseLeftStick
Definition: TankDrive.h:554
TankDrive::setUseHardStop
void setUseHardStop(bool use)
Definition: TankDrive.h:246
TankDrive::setDriveStick
void setDriveStick(JoystickController &driveStick)
Definition: TankDrive.h:196
TankDrive::fTurnDecelerationScale
unsigned fTurnDecelerationScale
Definition: TankDrive.h:566
JoystickController::State::analog
Analog analog
Definition: JoystickController.h:130
TankDrive::fChannelMixing
bool fChannelMixing
Definition: TankDrive.h:552
TankDrive::setThrottleAccelerationScale
void setThrottleAccelerationScale(unsigned scale)
Definition: TankDrive.h:149
TankDrive::setTurnDecelerationScale
void setTurnDecelerationScale(unsigned scale)
Definition: TankDrive.h:179
TankDrive::fSerialLatency
uint32_t fSerialLatency
Definition: TankDrive.h:561
JoystickController::Button::r1
uint8_t r1
Definition: JoystickController.h:59
TankDrive::setTurnInverted
void setTurnInverted(bool invert)
Definition: TankDrive.h:117
TankDrive::setUseLeftStick
void setUseLeftStick()
Definition: TankDrive.h:251
TargetSteering
Definition: TargetSteering.h:6
TankDrive::fThrottleInverted
bool fThrottleInverted
Definition: TankDrive.h:557
JoystickController::State::button
Button button
Definition: JoystickController.h:131
JoystickController::AnalogStick::rx
int8_t rx
Definition: JoystickController.h:11
TankDrive::setChannelMixing
void setChannelMixing(bool mixing)
Definition: TankDrive.h:97
TankDrive::fUseHardStop
bool fUseHardStop
Definition: TankDrive.h:556
TankDrive::fLastCommand
uint32_t fLastCommand
Definition: TankDrive.h:562
TankDrive::driveStick
void driveStick(JoystickController *stick, float speedModifier)
Definition: TankDrive.h:346
TankDrive::fTurnAccelerationScale
unsigned fTurnAccelerationScale
Definition: TankDrive.h:565
JoystickController::Analog::stick
AnalogStick stick
Definition: JoystickController.h:35
TankDrive::setMaxSpeed
void setMaxSpeed(float modifier)
Definition: TankDrive.h:137
JoystickController::AnalogStick::ly
int8_t ly
Definition: JoystickController.h:10
TankDrive::getEnable
bool getEnable()
Definition: TankDrive.h:72
TankDrive::setTurnAccelerationScale
void setTurnAccelerationScale(unsigned scale)
Definition: TankDrive.h:169
TankDrive::setup
virtual void setup() override
Subclasses must implement this function to perform any necessary setup that cannot happen in the cons...
Definition: TankDrive.h:68
TankDrive::setTargetSteering
void setTargetSteering(TargetSteering *target)
Definition: TankDrive.h:216
TankDrive::useThrottle
bool useThrottle()
Definition: TankDrive.h:221
TankDrive::fWasConnected
bool fWasConnected
Definition: TankDrive.h:550
TankDrive
Base template of automatic forwarder from i2c to CommandEvent.
Definition: TankDrive.h:37
TankDrive::fScaling
bool fScaling
Definition: TankDrive.h:553
TankDrive::getGuestSpeedModifier
float getGuestSpeedModifier()
Definition: TankDrive.h:206
TankDrive::fUseThrottle
bool fUseThrottle
Definition: TankDrive.h:555
TankDrive::setAccelerationScale
void setAccelerationScale(unsigned scale)
Definition: TankDrive.h:184
JoystickController.h
TankDrive::setSerialLatency
void setSerialLatency(uint32_t ms)
Definition: TankDrive.h:87
TankDrive::setThrottleDecelerationScale
void setThrottleDecelerationScale(unsigned scale)
Definition: TankDrive.h:159
TankDrive::getThrottle
virtual float getThrottle()
Definition: TankDrive.h:305
TankDrive::getTurnAccelerationScale
unsigned getTurnAccelerationScale()
Definition: TankDrive.h:164
MOTOR_DEBUG_PRINTLN
#define MOTOR_DEBUG_PRINTLN(s)
Definition: TankDrive.h:17
TankDrive::getThrottleDecelerationScale
unsigned getThrottleDecelerationScale()
Definition: TankDrive.h:154
TankDrive::fMotorsStopped
bool fMotorsStopped
Definition: TankDrive.h:551
JoystickController::Button::l1
uint8_t l1
Definition: JoystickController.h:58
MOTOR_DEBUG_PRINT
#define MOTOR_DEBUG_PRINT(s)
Definition: TankDrive.h:16
JoystickController::Analog::button
AnalogButton button
Definition: JoystickController.h:36
TankDrive::getScaling
bool getScaling()
Definition: TankDrive.h:122
TargetSteering::getTurning
float getTurning()
Definition: TargetSteering.h:37
JoystickController::AnalogStick::ry
int8_t ry
Definition: JoystickController.h:12
TankDrive::setDecelerationScale
void setDecelerationScale(unsigned scale)
Definition: TankDrive.h:190
TankDrive::fGuestStick
JoystickController * fGuestStick
Definition: TankDrive.h:547
TankDrive::useLeftStick
bool useLeftStick()
Definition: TankDrive.h:231
TankDrive::getTurnDecelerationScale
unsigned getTurnDecelerationScale()
Definition: TankDrive.h:174
TankDrive::motor
virtual void motor(float left, float right, float throttle)=0
JoystickController
Definition: JoystickController.h:4
TankDrive::getActiveStick
JoystickController * getActiveStick()
Definition: TankDrive.h:268
TankDrive::fTargetSteering
TargetSteering * fTargetSteering
Definition: TankDrive.h:548
TargetSteering.h
JoystickController::AnalogButton::r2
uint8_t r2
Definition: JoystickController.h:23
TankDrive::setGuestSpeedModifier
void setGuestSpeedModifier(float maxGuestSpeed)
Definition: TankDrive.h:211
TankDrive::getChannelMixing
bool getChannelMixing()
Definition: TankDrive.h:92
TargetSteering::getThrottle
float getThrottle()
Definition: TargetSteering.h:32
TankDrive::setScaling
void setScaling(bool scaling)
Definition: TankDrive.h:127
TankDrive::stop
virtual void stop()
Definition: TankDrive.h:261
TankDrive::throttleSpeed
virtual float throttleSpeed(float speedModifier)
Definition: TankDrive.h:322
TankDrive::setUseThrottle
void setUseThrottle(bool use)
Definition: TankDrive.h:241
TankDrive::TankDrive
TankDrive(JoystickController &driveStick)
Constructor.
Definition: TankDrive.h:46