Skip to content
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

STOP_AND_RESET_ENCODER often doesn't stop motors #899

Open
pmichaud opened this issue Jan 4, 2024 · 4 comments
Open

STOP_AND_RESET_ENCODER often doesn't stop motors #899

pmichaud opened this issue Jan 4, 2024 · 4 comments
Labels
bug Something isn't working

Comments

@pmichaud
Copy link

pmichaud commented Jan 4, 2024

tl;dr: Switching a DcMotorEx into STOP_AND_RESET_ENCODER mode doesn't always stop the motor -- the motor continues to receive power. Here's the bottom-line image of the issue at work, where a motor is in STOP_AND_RESET_ENCODER mode but the motor is drawing nearly 7 amps as it has reached its mechanical limit of travel and is stalled:

image

This issue was first identified and has been discussed at https://ftc-community.firstinspires.org/t/stop-and-reset-encoder-sometimes-doesnt-stop-motor/922 , along with some potential workarounds. I've also made a YouTube video that demonstrates the problem at https://youtu.be/rkFPpIvgoFs .

The bottom line so far seems to be that executing .setMode(STOP_AND_RESET_ENCODER) within 470ms (0.47s) of switching a motor to RUN_USING_ENCODER or RUN_TO_POSITION will reset the encoder value but will continue powering the motor according to the previous mode. A simple program demonstrating this behavior is attached as TRunMode.java.txt . I can also provide additional video demonstration if desired.

This incorrect/undocumented behavior seems to have been the "silent killer" for many of our team's burnt-out (literally) motors and degraded batteries over the past several seasons, as motors ended up in stall conditions for long periods of time when the program indicated they should be idle/depowered.

The Javadocs (https://javadoc.io/doc/org.firstinspires.ftc/RobotCore/latest/com/qualcomm/robotcore/hardware/DcMotor.html) claim that a side effect of STOP_AND_RESET_ENCODER is that power is removed from the motor. There's a blurb mentioning that some motor controllers will "automatically transition to a different mode after the reset" but if this is occurring, it's happening silently -- i.e. .getMode() still reports STOP_AND_RESET_ENCODER even as it continues sending power to the motor. It would also surprise me if the REV controllers are part of the category of "automatically transitioning controllers", but perhaps they are the reason for the additional blurb in the Javadocs.

At the least, the fact that STOP_AND_RESET_ENCODER doesn't actually remove power to a motor in some circumstances should be mentioned in the documentation. As our team has now discovered, mechanisms using limit switches and having mechanical limits on travel can easily find the motors placed in a stall condition because the STOP_AND_RESET_ENCODER didn't actually remove power as expected/documented.

Ideally the mode would be fixed so that the 0.4sec delay isn't needed and STOP_AND_RESET_ENCODER always does what it claims.

If the REV controllers are in the class of controller that automatically transitions to another mode after resetting the encoder, then the .getMode() method should reflect the results of that transition.

Another improvement might be to provide a .resetEncoder() API method that doesn't change the mode of the DcMotor at all -- a lot of beginner-level programming could be greatly simplified if this feature were available. The most common example is switching between RUN_USING_ENCODER and RUN_TO_POSITION for manual and "automatic preset" positioning of hardware mechanisms. Yes, a work around for this is for programmers to maintain their own "zero offset" variable in code, but this adds some level of complexity to coding and a rich source of bugs/edge cases to consider, which is more challenging for newer programmers and coaches. Setting a zero-point without changing the run state really feels like it's a fundamental operation that should be made more available in the API.

I'm glad to provide more details as needed, either in this issue ticket or on the community forum thread. Thanks for reading.

@gearsincorg
Copy link

gearsincorg commented Jan 4, 2024

Hi I read this and was pretty surpized that I had never encountered it....

I will say that I have always beleived that STOP_AND RESET_ENCODERS did remove power from the motors, but I admit I typically explicitly set the motor power to zero as well. There were some very odd timing constraints when resetting the motor controller encoders back in the days of ModernRobotics, but none of that code should exist any more....

While you do further tests, I would be interested to see if any of this is triggered explicitly from using DCMotorEx rather than DC Motor. I know DCMotorEx is required for setVelocity, but if you were to temporarilty replace this with setPower, you could revert to using plain DCMotor.

edit: In re-watching the video, it seems that the mode is not actally being set to STOP_AND_RESET_ENCODER as the encoder value is ALSO not zero.

edit: While looking at the video I realized that the STOP_AND_RESET_ENCODER mode does not seem to actually be in effect, because not only is the motor not stopping, but it's also not resetting the encoder. I wonder if this speaks to a confusion somewhere in that the SDK (software) and the HUB (firmware) are not in agreement about the current mode. The SDK probably caches the motor state, and power (with a 400 mS refresh ??), so perhaps it's getting confused.

@pmichaud
Copy link
Author

pmichaud commented Jan 4, 2024

The encoder value does actually reset to zero. Keep in mind that it resets the encoder at the point where .setMode(STOP_AND_RESET_ENCODER) is performed (one shot, not continuous), but if the mechanism continues moving while in SARE mode the encoder will continue to update from the new zero point. So the -13 and -11 values that are being displayed in the original video are because the elevator has continued moving past the magnetic limit switch detection point to its physical limit, not because the mode failed to reset the encoder.

If you try the experiment with the TRunMode.java sample attached to this issue ticket with a motor that isn't mechanically limited (as the elevator is mechanically limited in the youtube video), you can easily observe that the encoder does get reset to zero when STOP_AND_RESET_ENCODER is invoked, but then the current position updates from that new zero position as the motor continues spinning. (I went ahead and made a video of this, at https://www.youtube.com/watch?v=J2L_vV2dSN0 .)

I'll test with DcMotor at some point... but we really prefer to use .setVelocity() on our devices (it's the current recommendation, as I understand it), and not have to go back to .setPower() as a workaround. Also, we want/need to be monitoring current draw now, and that's available only via the DcMotorEx class.

Pm

@gearsincorg
Copy link

gearsincorg commented Jan 5, 2024

There is a checkered history behind RESET_ENCODER (same as STOP_AND_RESET_ENCODERS) so this is a possible clue to this issue.

Note: I wasn't suggesting a permanent switch to setPower(), simply proposing a test to see if it changed the behavior. So, if you get a chance it may accelerate finding a solution.

Based on what you are seeing, my personal opinion (not yet based on any facts) is that the system is performing the encoder reset, and then transitioning back into eithe RUN_WITHOUT_ENCODER or RUN_USING_ENCODER, but not correctly reporting the reverted state. The team is working the problem...

Phil.

@pmichaud
Copy link
Author

pmichaud commented Jan 5, 2024

I tried .setPower() overnight and found a funny behavior; described in https://ftc-community.firstinspires.org/t/stop-and-reset-encoder-sometimes-doesnt-stop-motor/922/7 .

The tl;dr is that performing a .setPower() while in RUNNING_WITHOUT_ENCODER mode seems to make any subsequent STOP_AND_RESET_ENCODER modes work entirely as expected, even after going into RUN_USING_ENCODER or RUN_TO_POSITION and then quickly switching back.

In the case of the TRunMode.java test script, simply executing .setPower(0) at any point prior to the while(opModeIsActive()) loop makes everything work properly in my tests.

As described in the community forum post... why a single .setPower(0) invocation in a seemingly unrelated RunMode has this effect is a complete mystery to me, and it's those sorts of mysteries that keep me awake at night because we can't be sure that some other bizarre behind-the-scenes behavior won't cause it all to stop working again.

Pm

@NoahAndrews NoahAndrews added the bug Something isn't working label Apr 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants