Refactor arcade heading hold, reverse steering - #115
Open
SaintSampo wants to merge 6 commits into
Open
Conversation
Replace reset_heading/turning flags with a single _holding_heading flag and simplify arcade mixing logic. Use early returns, keep wheel-mixing/scaling behavior, and centralize IMU-assisted straight driving: capture heading on entry, hold it while straight, and clear the hold when turning. Improves readability and fixes heading recapture behavior when transitioning between turning and straight driving.
When driving backward the turn input is inverted so the robot steers toward the joystick the same way as when driving forward. Adds a check in DifferentialDrive to negate `turn` if `straight` is negative before mixing, preserving the existing mixing and scaling logic and preventing reversed steering behavior.
Collaborator
|
Deadbanding should not be handled in Arcade. That is for a program to
handle.
…On Thu, Aug 6, 2026 at 6:19 PM Jacob Williams ***@***.***> wrote:
Summary
Cleans up arcade() and its IMU heading-hold, and fixes two teleop feel
issues. Single file, differential_drive.py.
Changes
-
*Collapsed the heading-hold state machine.* The two flags turning +
reset_heading are replaced by one _holding_heading. Same behavior
across every transition, far less to reason about. arcade() is
flattened to early returns instead of 3-deep nesting, and the misnamed
left_speed/right_speed (they're efforts) become left/right.
-
*Joystick deadband (0.1).* Inputs below the threshold on either axis
snap to zero, so idle-stick drift no longer creeps or slowly turns the
robot. Also means near-center turn resolves to exactly 0, so heading-hold
engages instead of being disabled by drift.
-
*Reverse steering fix.* Pushing back-and-left used to curve the robot
*right* (the turn kept the same rotation direction as forward). Turn
is now flipped when reversing, so the robot steers toward the stick either
way.
-
*Stop forgets the held heading.* A neutral (0, 0) clears
_holding_heading, so resuming straight recaptures the current heading
rather than steering back toward the pre-stop one.
-
*Fresh PID per straight segment.* heading_pid.clear_history() on
entering straight prevents a prior turn's elapsed time from leaking into
the controller's first derivative/integral step.
-
*Per-board heading gains.* The single kp=0.075, kd=0.001 is replaced
with tuned values: non-Nano kp=0.064, kd=0.0045, Nano kp=0.014,
kd=0.001.
Notes
- Behavior changes worth knowing for existing code: the deadband, the
reverse turn-flip, and the new heading gains all change how teleop drives.
- self.turning and self.reset_heading are gone (nothing else in XRPLib
referenced them); the internal flag is now self._holding_heading.
Testing
Driven via gamepad teleop on hardware — deadband, reverse steering, and
straight-line heading hold all confirmed by feel. Autonomous straight()/
turn() are unaffected (they don't use heading_pid).
------------------------------
You can view, comment on, or merge this pull request online at:
#115
Commit Summary
- 9d4b585
<9d4b585>
Refactor IMU heading hold in differential_drive
- 43ba7d4
<43ba7d4>
Clear holding heading when drive stopped
- 6115cd9
<6115cd9>
Add joystick deadband and PID reset for heading
- 10538ad
<10538ad>
Add NanoXRP-specific heading PID gains
- aade436
<aade436>
Invert turn input when reversing
File Changes
(1 file <https://github.com/Open-STEM/XRP_MicroPython/pull/115/files>)
- *M* XRPLib/differential_drive.py
<https://github.com/Open-STEM/XRP_MicroPython/pull/115/files#diff-cb32d1534df39f42a083149b40f1dcb976cf643683e2f632c47258987cb6c4d0>
(79)
Patch Links:
- https://github.com/Open-STEM/XRP_MicroPython/pull/115.patch
- https://github.com/Open-STEM/XRP_MicroPython/pull/115.diff
—
Reply to this email directly, view it on GitHub
<#115?email_source=notifications&email_token=AAKMHRB6GUVB5OSN4CWCYGL5IUAABA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DEMRUGE4TIMBSGWTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVRTG633UMVZF6Y3MNFRWW>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAKMHRDLV4IOM5MLSIGROY35IUAABAVCNFSNUABFKJSXA33TNF2G64TZHM3DAOJWG44TIOJVHNEXG43VMU5TKMBYGUYTAMZTGQZ2C5QC>
.
Triage notifications, keep track of coding agent tasks and review pull
requests on the go with GitHub Mobile for iOS
<https://github.com/notifications/mobile/ios/AAKMHRGF5LDTWKLZHVUUKLT5IUAABA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DEMRUGE4TIMBSGWTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVJTG633UMVZF62LPOM>
and Android
<https://github.com/notifications/mobile/android/AAKMHRBGHXYVITQOB7L6KHT5IUAABA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DEMRUGE4TIMBSGWTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVZTG633UMVZF6YLOMRZG62LE>.
Download it today!
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
Member
Author
|
My thinking was that without a deadband, there is not much point of having a control loop maintain heading. A stick will almost never be at exactly zero. Very few users are going to know to add a deadband. But I can remove it, if it is technically more correct. Future idea: I think a drivetrain class like this should make it easy for users to set and tune a min_input, max_input, deadband, and input exponential. Low priority but I want to revisit this at some point. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Cleans up
arcade()and its IMU heading-hold, and fixes two teleop feel issues. Single file,differential_drive.py.Changes
Collapsed the heading-hold state machine. The two flags
turning+reset_headingare replaced by one_holding_heading. Same behavior across every transition, far less to reason about.arcade()is flattened to early returns instead of 3-deep nesting, and the misnamedleft_speed/right_speed(they're efforts) becomeleft/right.Joystick deadband (0.1). Inputs below the threshold on either axis snap to zero, so idle-stick drift no longer creeps or slowly turns the robot. Also means near-center turn resolves to exactly 0, so heading-hold engages instead of being disabled by drift.
Reverse steering fix. Pushing back-and-left used to curve the robot right (the turn kept the same rotation direction as forward). Turn is now flipped when reversing, so the robot steers toward the stick either way.
Stop forgets the held heading. A neutral
(0, 0)clears_holding_heading, so resuming straight recaptures the current heading rather than steering back toward the pre-stop one.Fresh PID per straight segment.
heading_pid.clear_history()on entering straight prevents a prior turn's elapsed time from leaking into the controller's first derivative/integral step.Per-board heading gains. The single
kp=0.075, kd=0.001is replaced with tuned values: non-Nanokp=0.064, kd=0.0045, Nanokp=0.014, kd=0.001.Notes
self.turningandself.reset_headingare gone (nothing else in XRPLib referenced them); the internal flag is nowself._holding_heading.Testing
Driven via gamepad teleop on hardware — deadband, reverse steering, and straight-line heading hold all confirmed by feel. Autonomous
straight()/turn()are unaffected (they don't useheading_pid).