-
-
Notifications
You must be signed in to change notification settings - Fork 7
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
Motor.run_target() raises RuntimeError #786
Comments
Nice find 👍 , I'm happy to look into it. |
Which motors are connected here? They all have different acceleration profiles, which could be relevant for reproduction. |
I used the gray medium motors from Robot Inventor for this test. |
This probably fails in We should be able to do something like: old_trajectory = steer.control.trajectory()
try:
steer.run_target(1400, -steer_angle, Stop.HOLD, False)
except:
print(steer_angle)
print(old_trajectory)
print(steer.control.limits())
print(steer.control.trajectory()) Then we can add the failed case to |
For what it's worth, a contributing factor is this. This is an old hack that should no longer be used. steer.control.pid(kp=old_kp*4, kd=old_kd*0.4) |
from pybricks.pupdevices import Motor, Remote
from pybricks.parameters import Port, Direction, Stop, Button, Color
from pybricks.hubs import ThisHub
from pybricks.tools import wait
from pybricks import version
print(version)
# Initialize the motors.
steer = Motor(Port.A)
front = Motor(Port.B, Direction.COUNTERCLOCKWISE)
# Connect to the remote and set the light on the remote
remote = Remote()
remote.light.on(Color.GREEN)
# Initialize the hub.
hub = ThisHub()
hub.light.on(Color.GREEN)
# Read the current settings
old_kp, old_ki, old_kd, _, _ = steer.control.pid()
# Set new values
steer.control.pid(kp=old_kp*4, kd=old_kd*0.4)
# Set initial top speed value
top_speed = 100
# Find the steering endpoint on the left and right.
# The middle is in between.
# left_end = steer.run_until_stalled(-200, then=Stop.HOLD)
# right_end = steer.run_until_stalled(200, then=Stop.HOLD)
# We are now at the right. Reset this angle to be half the difference.
# That puts zero in the middle.
# steer.reset_angle((right_end - left_end)/2)
# steer.run_target(speed=200, target_angle=0, wait=False)
# Set steering angle for the buggy
# steer_angle = (((right_end - left_end)/2)-5)
# print('steer angle:',steer_angle)
steer_angle = 167.5
# Now we can start driving!
while True:
# Check which buttons are pressed.
pressed = remote.buttons.pressed()
old_trajectory = steer.control.trajectory()
try:
# Choose the steer angle based on the right controls.
if Button.LEFT_PLUS in pressed:
steer.run_target(1400, -steer_angle, Stop.HOLD, False)
elif Button.LEFT_MINUS in pressed:
steer.run_target(1400, steer_angle, Stop.HOLD, False)
else:
steer.track_target(0)
except RuntimeError:
print(steer_angle)
print(old_trajectory)
print(steer.control.limits())
print(steer.control.trajectory())
hub.speaker.beep()
# Top speed controls
if Button.LEFT in pressed:
top_speed = 75
if Button.RIGHT in pressed:
top_speed = 100
if ((Button.RIGHT in pressed) and (Button.LEFT in pressed)):
top_speed = 40
# Choose the drive speed based on the left controls.
drive_speed = 0
if Button.RIGHT_PLUS in pressed:
drive_speed -= top_speed
if Button.RIGHT_MINUS in pressed:
drive_speed += top_speed
# Apply the selected speed.
front.dc(drive_speed)
# Wait.
wait(10) |
Here are two cases:
|
Running with this diff gives a bit more detail: diff --git a/pybricks/common/pb_type_control.c b/pybricks/common/pb_type_control.c
index b96e5edc..620f9649 100644
--- a/pybricks/common/pb_type_control.c
+++ b/pybricks/common/pb_type_control.c
@@ -213,16 +213,16 @@ STATIC mp_obj_t common_Control_trajectory(mp_obj_t self_in) {
if (pbio_control_is_active(self->control)) {
parms[0] = mp_obj_new_int(0);
- parms[1] = mp_obj_new_int(trj->t1 / 10);
- parms[2] = mp_obj_new_int(trj->t2 / 10);
- parms[3] = mp_obj_new_int(trj->t3 / 10);
+ parms[1] = mp_obj_new_int(trj->t1);
+ parms[2] = mp_obj_new_int(trj->t2);
+ parms[3] = mp_obj_new_int(trj->t3);
parms[4] = mp_obj_new_int(0);
- parms[5] = mp_obj_new_int(trj->th1 / 1000);
- parms[6] = mp_obj_new_int(trj->th2 / 1000);
- parms[7] = mp_obj_new_int(trj->th3 / 1000);
- parms[8] = mp_obj_new_int(trj->w0 / 10);
- parms[9] = mp_obj_new_int(trj->w1 / 10);
- parms[10] = mp_obj_new_int(trj->w3 / 10);
+ parms[5] = mp_obj_new_int(trj->th1);
+ parms[6] = mp_obj_new_int(trj->th2);
+ parms[7] = mp_obj_new_int(trj->th3);
+ parms[8] = mp_obj_new_int(trj->w0);
+ parms[9] = mp_obj_new_int(trj->w1);
+ parms[10] = mp_obj_new_int(trj->w3);
parms[11] = mp_obj_new_int(trj->a0);
parms[12] = mp_obj_new_int(trj->a2);
return mp_obj_new_tuple(13, parms); |
The error is nagative time t1 of |
Fix incorrect acceleration for rounded speed values, causing negative duration. Also assert more time values for easier debugging. See pybricks/support#786
For short maneuvers, t1 can be 0. If time is also 0, it wouldn't get into the first segment of the trajectory. See pybricks/support#786
While sub-degree maneuvers cannot be entered by users, we can still have sub-degree maneuvers if a new command is started while the trajectory is already near the target. This happens relatively often when restarting run_target towards the same target in a tight loop. See pybricks/support#786
If t1=0, the speed skips to w1 right away. Even though w0 is not used in that case, it still makes sense to give it a well defined value. This simplifies debugging and is useful for validation in tests. See pybricks/support#786
@dlech Is it better with e.g. pybricks/pybricks-micropython@9af922d? (Ignore the shaking, that's just excessive PID as mentioned above, but it may help make the actual bug occur more often.) |
I can no longer reproduce the problem, so seems to be fixed, thanks! |
Describe the bug
What is the problem?
After some time, the program below crashes one of the
steer.run_target()
lines with aRuntimeError
. The time is variable but usually less than a minute (pressing buttons on the remote to steer during this time).Full output:
To reproduce
Expected behavior
What did you expect to happen instead?
Program should run forever.
The text was updated successfully, but these errors were encountered: