-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add dshot_reversed_motors: per-motor spin direction via DShot commands 20/21 #12022
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: maintenance-11.x
Are you sure you want to change the base?
Changes from all commits
da63a33
2d3cd98
69a8cfb
6db9c5b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53,6 +53,8 @@ | |
| #include "flight/pid.h" | ||
| #include "flight/servos.h" | ||
|
|
||
| #include "io/beeper.h" | ||
|
|
||
| #include "navigation/navigation.h" | ||
|
|
||
| #include "rx/rx.h" | ||
|
|
@@ -89,13 +91,16 @@ PG_RESET_TEMPLATE(reversibleMotorsConfig_t, reversibleMotorsConfig, | |
| .neutral = SETTING_3D_NEUTRAL_DEFAULT | ||
| ); | ||
|
|
||
| PG_REGISTER_WITH_RESET_TEMPLATE(motorConfig_t, motorConfig, PG_MOTOR_CONFIG, 11); | ||
| PG_REGISTER_WITH_RESET_TEMPLATE(motorConfig_t, motorConfig, PG_MOTOR_CONFIG, 12); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2. Upgrades erase existing motor settings Registering PG_MOTOR_CONFIG as version 12 makes pgLoad() reject every stored version-11 record after first resetting the complete group. Upgrading existing installations therefore defaults the PWM protocol, rate, minimum command, idle offset, and pole count along with initializing the new direction field. Agent Prompt
|
||
|
|
||
| PG_RESET_TEMPLATE(motorConfig_t, motorConfig, | ||
| .motorPwmProtocol = SETTING_MOTOR_PWM_PROTOCOL_DEFAULT, | ||
| .motorPwmRate = SETTING_MOTOR_PWM_RATE_DEFAULT, | ||
| .mincommand = SETTING_MIN_COMMAND_DEFAULT, | ||
| .motorPoleCount = SETTING_MOTOR_POLES_DEFAULT, // Most brushless motors that we use are 14 poles | ||
| #ifdef USE_DSHOT | ||
| .dshotReversedMotors = SETTING_DSHOT_REVERSED_MOTORS_DEFAULT, | ||
| #endif | ||
| ); | ||
| PG_REGISTER_ARRAY_WITH_RESET_FN(timerOverride_t, HARDWARE_TIMER_DEFINITION_COUNT, timerOverrides, PG_TIMER_OVERRIDE_CONFIG, 0); | ||
|
|
||
|
|
@@ -1003,6 +1008,74 @@ bool areMotorsStopped(void) | |
| return motor[0] == motorZeroCommand; | ||
| } | ||
|
|
||
| #ifdef USE_DSHOT | ||
| /* | ||
| * DShot commands 20/21 are not stored by the ESC: it forgets them when it restarts, and | ||
| * without telemetry the FC cannot see an ESC restart - the battery plugged in after USB | ||
| * is the everyday case. So the configured directions go out again on every arm, as soon | ||
| * as the setting changes, and every DSHOT_SPIN_DIRECTION_REFRESH_US while disarmed. On | ||
| * arm the command frames replace the first throttle frames, so an ESC that was listening | ||
| * has its direction before it gets throttle. | ||
| */ | ||
| #define DSHOT_SPIN_DIRECTION_POLL_US 100000 | ||
| #define DSHOT_SPIN_DIRECTION_REFRESH_US 2000000 | ||
|
|
||
| static uint16_t dshotSpinDirectionSent = 0; // reversed mask the ESCs last received | ||
| static timeUs_t dshotSpinDirectionSentAtUs = 0; | ||
| static timeUs_t dshotSpinDirectionPolledAtUs = 0; | ||
|
|
||
| static uint16_t dshotReversedMotorMask(void) | ||
| { | ||
| return motorConfig()->dshotReversedMotors & ((1u << motorCount) - 1); | ||
| } | ||
|
|
||
| void dshotSpinDirectionApply(bool invert) | ||
| { | ||
| if (!isMotorProtocolDshot()) { | ||
| return; | ||
| } | ||
|
|
||
| const uint16_t allMotors = (1u << motorCount) - 1; | ||
| const uint16_t mask = invert ? (~dshotReversedMotorMask() & allMotors) : dshotReversedMotorMask(); | ||
|
|
||
| sendDShotSpinDirection(mask); | ||
| dshotSpinDirectionSent = mask; | ||
| dshotSpinDirectionSentAtUs = micros(); | ||
|
Comment on lines
+1041
to
+1043
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 3. Full queues retain stale motor direction dshotSpinDirectionApply records the requested mask and timestamp even when the void sendDShotSpinDirection call is discarded by a full circular buffer. After eight frames are queued, this suppresses the changed-mask retry for two seconds, so affected electronic speed controllers continue using their previous direction. Agent Prompt
|
||
| } | ||
|
|
||
| void NOINLINE dshotSpinDirectionUpdate(timeUs_t currentTimeUs) | ||
| { | ||
| // Called from a busy loop; one evaluation per poll interval is plenty | ||
| if (currentTimeUs - dshotSpinDirectionPolledAtUs < DSHOT_SPIN_DIRECTION_POLL_US) { | ||
| return; | ||
| } | ||
| dshotSpinDirectionPolledAtUs = currentTimeUs; | ||
|
|
||
| if (!isMotorProtocolDshot()) { | ||
| return; | ||
| } | ||
|
|
||
| const uint16_t mask = dshotReversedMotorMask(); | ||
|
|
||
| // All normal and the last frame (if any) was all normal: quiet while disarmed, tryArm() still sends it | ||
| if (mask == 0 && dshotSpinDirectionSent == 0) { | ||
| return; | ||
| } | ||
|
|
||
| if (mask == dshotSpinDirectionSent && currentTimeUs - dshotSpinDirectionSentAtUs < DSHOT_SPIN_DIRECTION_REFRESH_US) { | ||
| return; | ||
| } | ||
|
|
||
| // Only a stopped motor listens to commands (the motor test counts as running), and an | ||
| // ESC that is still playing a beacon tone ignores them too | ||
| if (areMotorsRunning() || currentTimeUs - getLastDshotBeeperCommandTimeUs() < getDShotBeaconGuardDelayUs()) { | ||
| return; | ||
| } | ||
|
|
||
| dshotSpinDirectionApply(false); | ||
| } | ||
| #endif | ||
|
|
||
| uint16_t getMaxThrottle(void) { | ||
|
|
||
| static uint16_t throttle = 0; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3. Changed motor directions can be delayed
🐞 Bug≡ CorrectnessAgent Prompt
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools