[Doc] How to reset angle for mechanically constrained mechanisms
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).
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().
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.
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?
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.
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.
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.
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.
Here is a visualization of @davecparker 's case:
We can include this in the user guide along with an example.