support icon indicating copy to clipboard operation
support copied to clipboard

[Bug] DriveBase.distance() changes after resetting wheel motors' angles

Open donmerendolo opened this issue 1 year ago • 4 comments

Describe the bug What is the problem? Hi, I am coaching an FLL team and was testing the robot today using relative distances (passing target_distance - robot.distance() to DriveBase.straight()). I noticed that the robot sometimes moved a lot and other times it moved very little. Later today I was able to isolate the issue and found out that resetting the wheel motors' angles changed the measured distance value. I don't know if it's relevant but we use the SPIKE Prime.

To reproduce I made this program that shows that DriveBase distance changes without moving the motors:

from pybricks.hubs import PrimeHub
from pybricks.pupdevices import Motor
from pybricks.parameters import Button, Color, Direction, Port, Side, Stop, Axis, Icon
from pybricks.robotics import DriveBase
from pybricks.tools import wait, StopWatch, Matrix

hub = PrimeHub()

left_wheel = Motor(Port.B, Direction.COUNTERCLOCKWISE)
right_wheel = Motor(Port.A, Direction.CLOCKWISE)

robot = DriveBase(left_wheel, right_wheel, 62.4, 110)

print("Before reset:")
print("robot distance:", robot.distance())
print("left_wheel angle:", left_wheel.angle())
print("right_wheel angle:", right_wheel.angle())
print()

left_wheel.reset_angle(0)
print("After left_wheel reset:")
print("robot distance:", robot.distance())
print("left_wheel angle:", left_wheel.angle())
print("right_wheel angle:", right_wheel.angle())
print()

right_wheel.reset_angle(0)
print("After right_wheel reset:")
print("robot distance:", robot.distance())
print("left_wheel angle:", left_wheel.angle())
print("right_wheel angle:", right_wheel.angle())
print()

Which outputs this:

Before reset:
robot distance: 0
left_wheel angle: 97
right_wheel angle: 158

After left_wheel reset:
robot distance: -27
left_wheel angle: 0
right_wheel angle: 158

After right_wheel reset:
robot distance: -70
left_wheel angle: 0
right_wheel angle: 0

As you can see, the robot's measured distance is changed without even moving the motors.

Expected behavior I think the measured distance should stay the same after resetting the drivebase's motors.

Resetting distance after resetting the motors solves this issue but I spent some time figuring this out.

donmerendolo avatar Feb 16 '24 22:02 donmerendolo

Thank you! I can see that this could be confusing.

Another way to resolve this would be to reset the motors before creating the drive base:

left_wheel = Motor(Port.B, Direction.COUNTERCLOCKWISE)
left_wheel.reset_angle(0)
right_wheel = Motor(Port.A, Direction.CLOCKWISE)
right_wheel.reset_angle(0)

robot = DriveBase(left_wheel, right_wheel, 62.4, 110)

Resetting distance after resetting the motors solves this issue but I spent some time figuring this out.

Maybe we should do this automatically, and add a note about it in the docs.

Related to this, maybe we should also reset the angle when switching to/from using the gyro.

laurensvalk avatar Feb 17 '24 13:02 laurensvalk

Thanks ☺️

Another way to resolve this would be to reset the motors before creating the drive base:

left_wheel = Motor(Port.B, Direction.COUNTERCLOCKWISE)
left_wheel.reset_angle(0)
right_wheel = Motor(Port.A, Direction.CLOCKWISE)
right_wheel.reset_angle(0)

robot = DriveBase(left_wheel, right_wheel, 62.4, 110)

Even then, if the robot references itself with a wall (for example), resets distance, then resets motors, the measured distance will change too, right? This year, in my team's robot we sometimes want to turn with a single wheel, so we reset motors in the wall too (although I don't think it makes much sense to use relative angle here instead of gyro or absolute angle).

donmerendolo avatar Feb 17 '24 22:02 donmerendolo

Thank you. I think we haven't given the individual motor resets combined with drive base resets enough thought.

I agree that some changes would be helpful, and we can certainly do so. We just have to figure out what's "right", and then find a way to implement it as well.

Possible approach: (feel free to suggest others!)

  • when reset_angle is used on a single motor, change the firmware so that drive_base.distance() and angle() are not affected.
  • drivebase.reset() does not affect the individual motor, since it isn't clear what they should be reset to.

Would this solve your use case?

laurensvalk avatar Feb 18 '24 07:02 laurensvalk

That approach is exactly what I had in mind!! 😄

For solving our use case we have made a function similar to this to make sure we always reset distance after motors:

def reset_motors():
    left_wheel.reset_angle(0)
    right_wheel.reset_angle(0)
    drivebase.reset()

donmerendolo avatar Feb 18 '24 16:02 donmerendolo