support icon indicating copy to clipboard operation
support copied to clipboard

[Doc] How to reset angle for mechanically constrained mechanisms

Open davecparker opened this issue 3 years ago • 8 comments

Motor.run_target() always chooses the "shortest path" direction. There have been several situations I have found a need to specify the direction, as you can in LEGO Scratch, and I have run into this problem now trying to rewrite one for Pybricks. For example:

There is an arm that can travel from position 0 to 270, but can't go past that without breaking. At the beginning of the program, I want to return it to 0, regardless of where it was left last time. If it is past 180, runTarget to 0 will take it wrong way and break the model. In LEGO Scratch I can look at the angle and decide what to do with an if/else, but in Pybricks, I don't see a way to do it (with a single movement).

davecparker avatar Dec 30 '22 23:12 davecparker

I ran in to the same issue recently. In Pybricks, when the program starts, the motors are reset to the absolute position as read by the motor encoder which is between -180 and +180 . So when the position is "above 180", it is actually below 0. My case was slightly different since I wasn't starting a 0, but you could do something like this when the program starts:

if motor.angle() < -45:
    motor.reset_angle(360 + motor.angle())

Then it will be sure to turn in the correct direction to get to 0 when you use motor.run_target().

dlech avatar Dec 30 '22 23:12 dlech

Oops, I wrote that example thinking in 0-360 terms, gotta get used to +/-180.

if motor.angle() < -45:
    motor.reset_angle(360 + motor.angle())

Interesting, that's simpler than the workaround I came up with using logic + run_angle() and then a reset_angle(0) afterwards.

Neither is too obvious, though. Interesting problem, since the motor does not know how it got where it is at the beginning.

davecparker avatar Dec 31 '22 00:12 davecparker

Maybe a more obvious solution is to use motor.run_until_stalled() with low duty_limit to get to zero, then motor.reset_angle() to ensure the correct relative angle?

dlech avatar Dec 31 '22 00:12 dlech

In some cases maybe, in my current case there is no safe mechanical limit in either direction, it will stress the parts or cables going too far in either direction.

davecparker avatar Dec 31 '22 01:12 davecparker

Another alternative:

if motor.angle() < -45:
    motor.run_angle(500, -180)
    motor.reset_angle()

there is no safe mechanical limit in either direction

This is why the shortest_angle option in the block language is almost always a bad idea.

Motor.run_target() always chooses the "shortest path" direction.

I imagine you have now found that this is not actually the case.

laurensvalk avatar Jan 02 '23 13:01 laurensvalk

Motor.run_target() always chooses the "shortest path" direction.

I imagine you have now found that this is not actually the case.

Right, just the effect of that when using run_target(0) at the beginning of a program. For the Fast Block Flipper, I ended up using:

        if wrist.angle() < -90:   # then run_target would go the wrong way 
            wrist.reset_angle(360 + wrist.angle())  # forces counter-clockwise

        wrist.run_target(FULL_SPEED, 0)

as suggested by dlech, which is elegant and works well, just not very obvious.

BTW, while reading the docs to try to figure this out, I found myself unsure in the description of the two variants of motor.reset_angle() whether they would physically move the motor or just the relative 0 point, so maybe that could use some clearing up.

davecparker avatar Jan 02 '23 15:01 davecparker

Thanks, then we can close this issue.

maybe that could use some clearing up.

Please feel free to make a dedicated issue, including suggested text. It's better to create many small and specific issues than one larger one.

laurensvalk avatar Jan 02 '23 15:01 laurensvalk

Here is a visualization of @davecparker 's case:

image

We can include this in the user guide along with an example.

laurensvalk avatar Sep 13 '24 10:09 laurensvalk