Skip to content

Commit 7920923

Browse files
committed
pbio/drivebase: Fix synchronized pause state.
Now, the paused controller cannot unpause itself until all controllers are unpaused. This is simpler, and also generalizes to N motors when we go beyond drivebases. Partially fixes pybricks/support#1032
1 parent 26b8e62 commit 7920923

File tree

5 files changed

+44
-26
lines changed

5 files changed

+44
-26
lines changed

lib/pbio/include/pbio/control.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,14 @@ void pbio_control_get_reference(pbio_control_t *ctl, uint32_t time_now, const pb
165165

166166
void pbio_control_reset(pbio_control_t *ctl);
167167
void pbio_control_stop(pbio_control_t *ctl);
168-
void pbio_control_update(pbio_control_t *ctl, uint32_t time_now, const pbio_control_state_t *state, pbio_trajectory_reference_t *ref, pbio_dcmotor_actuation_t *actuation, int32_t *control);
168+
void pbio_control_update(
169+
pbio_control_t *ctl,
170+
uint32_t time_now,
171+
const pbio_control_state_t *state,
172+
pbio_trajectory_reference_t *ref,
173+
pbio_dcmotor_actuation_t *actuation,
174+
int32_t *control,
175+
bool *external_pause);
169176

170177
// Control status checks:
171178

lib/pbio/include/pbio/drivebase.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ typedef struct _pbio_drivebase_t {
2323
* True if a gyro or compass is used for heading control, else false.
2424
*/
2525
bool use_gyro;
26+
/**
27+
* Synchronization state to indicate that one or more controllers are paused.
28+
*/
29+
bool control_paused;
2630
pbio_servo_t *left;
2731
pbio_servo_t *right;
2832
pbio_control_t control_heading;

lib/pbio/src/control.c

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -216,14 +216,23 @@ static int32_t pbio_control_get_pid_kp(const pbio_control_settings_t *settings,
216216
/**
217217
* Updates the PID controller state to calculate the next actuation step.
218218
*
219-
* @param [in] ctl The control instance.
220-
* @param [in] time_now The wall time (ticks).
221-
* @param [in] state The current state of the system being controlled (control units).
222-
* @param [out] ref Computed reference point on the trajectory (control units).
223-
* @param [out] actuation Required actuation type.
224-
* @param [out] control The control output, which is the actuation payload (control units).
219+
* @param [in] ctl The control instance.
220+
* @param [in] time_now The wall time (ticks).
221+
* @param [in] state The current state of the system being controlled (control units).
222+
* @param [out] ref Computed reference point on the trajectory (control units).
223+
* @param [out] actuation Required actuation type.
224+
* @param [out] control The control output, which is the actuation payload (control units).
225+
* @param [inout] external_pause Whether to force the controller to pause using external information (in), and
226+
* whether the controller still needs pausing according to its own state (out).
225227
*/
226-
void pbio_control_update(pbio_control_t *ctl, uint32_t time_now, const pbio_control_state_t *state, pbio_trajectory_reference_t *ref, pbio_dcmotor_actuation_t *actuation, int32_t *control) {
228+
void pbio_control_update(
229+
pbio_control_t *ctl,
230+
uint32_t time_now,
231+
const pbio_control_state_t *state,
232+
pbio_trajectory_reference_t *ref,
233+
pbio_dcmotor_actuation_t *actuation,
234+
int32_t *control,
235+
bool *external_pause) {
227236

228237
// Get reference signals at the reference time point in the trajectory.
229238
// This compensates for any time we may have spent pausing when the motor was stalled.
@@ -290,7 +299,7 @@ void pbio_control_update(pbio_control_t *ctl, uint32_t time_now, const pbio_cont
290299

291300
// Position anti-windup in case of angle control (accumulated position error may not get too high)
292301
if (pbio_control_type_is_position(ctl)) {
293-
if (pause_integration) {
302+
if (pause_integration || *external_pause) {
294303
// We are at the torque limit and we should prevent further position error integration.
295304
pbio_position_integrator_pause(&ctl->position_integrator, time_now);
296305
} else {
@@ -300,7 +309,7 @@ void pbio_control_update(pbio_control_t *ctl, uint32_t time_now, const pbio_cont
300309
}
301310
// Position anti-windup in case of timed speed control (speed integral may not get too high)
302311
else {
303-
if (pause_integration) {
312+
if (pause_integration || *external_pause) {
304313
// We are at the torque limit and we should prevent further speed error integration.
305314
pbio_speed_integrator_pause(&ctl->speed_integrator, time_now, position_error);
306315
} else {
@@ -309,6 +318,9 @@ void pbio_control_update(pbio_control_t *ctl, uint32_t time_now, const pbio_cont
309318
}
310319
}
311320

321+
// Informs caller if pausing is still needed according to this controller's state.
322+
*external_pause = pause_integration;
323+
312324
// Check if controller is stalled, and set the status.
313325
pbio_control_status_set(ctl, PBIO_CONTROL_STATUS_STALLED,
314326
pbio_control_type_is_position(ctl) ?

lib/pbio/src/drivebase.c

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ static void pbio_drivebase_stop_drivebase_control(pbio_drivebase_t *db) {
164164
// Stop drivebase control so polling will stop
165165
pbio_control_stop(&db->control_distance);
166166
pbio_control_stop(&db->control_heading);
167+
db->control_paused = false;
167168
}
168169

169170
/**
@@ -291,6 +292,7 @@ pbio_error_t pbio_drivebase_get_drivebase(pbio_drivebase_t **db_address, pbio_se
291292
// Stop any existing drivebase controls
292293
pbio_control_reset(&db->control_distance);
293294
pbio_control_reset(&db->control_heading);
295+
db->control_paused = false;
294296

295297
// Reset both motors to a passive state
296298
pbio_drivebase_stop_servo_control(db);
@@ -405,13 +407,18 @@ static pbio_error_t pbio_drivebase_update(pbio_drivebase_t *db) {
405407
pbio_trajectory_reference_t ref_distance;
406408
int32_t distance_torque;
407409
pbio_dcmotor_actuation_t distance_actuation;
408-
pbio_control_update(&db->control_distance, time_now, &state_distance, &ref_distance, &distance_actuation, &distance_torque);
410+
bool distance_external_pause = db->control_paused;
411+
pbio_control_update(&db->control_distance, time_now, &state_distance, &ref_distance, &distance_actuation, &distance_torque, &distance_external_pause);
409412

410413
// Get reference and torque signals for heading control.
411414
pbio_trajectory_reference_t ref_heading;
412415
int32_t heading_torque;
413416
pbio_dcmotor_actuation_t heading_actuation;
414-
pbio_control_update(&db->control_heading, time_now, &state_heading, &ref_heading, &heading_actuation, &heading_torque);
417+
bool heading_external_pause = db->control_paused;
418+
pbio_control_update(&db->control_heading, time_now, &state_heading, &ref_heading, &heading_actuation, &heading_torque, &heading_external_pause);
419+
420+
// If either controller is paused, pause both.
421+
db->control_paused = distance_external_pause || heading_external_pause;
415422

416423
// If either controller coasts, coast both, thereby also stopping control.
417424
if (distance_actuation == PBIO_DCMOTOR_ACTUATION_COAST ||
@@ -430,19 +437,6 @@ static pbio_error_t pbio_drivebase_update(pbio_drivebase_t *db) {
430437
return PBIO_ERROR_FAILED;
431438
}
432439

433-
// Both controllers are able to stop the other when it stalls. This ensures
434-
// they complete at exactly the same time.
435-
if (pbio_control_type_is_position(&db->control_distance) &&
436-
pbio_position_integrator_is_paused(&db->control_distance.position_integrator)) {
437-
// If distance controller is paused, pause heading control too.
438-
pbio_position_integrator_pause(&db->control_heading.position_integrator, time_now);
439-
}
440-
if (pbio_control_type_is_position(&db->control_heading) &&
441-
pbio_position_integrator_is_paused(&db->control_heading.position_integrator)) {
442-
// If heading controller is paused, pause distance control too.
443-
pbio_position_integrator_pause(&db->control_distance.position_integrator, time_now);
444-
}
445-
446440
// The left servo drives at a torque and speed of (average) + (difference).
447441
int32_t feed_forward_left = pbio_observer_get_feedforward_torque(
448442
db->left->observer.model,

lib/pbio/src/servo.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ static pbio_error_t pbio_servo_update(pbio_servo_t *srv) {
9595

9696
// Calculate feedback control signal
9797
pbio_dcmotor_actuation_t requested_actuation;
98-
pbio_control_update(&srv->control, time_now, &state, &ref, &requested_actuation, &feedback_torque);
98+
bool external_pause = false;
99+
pbio_control_update(&srv->control, time_now, &state, &ref, &requested_actuation, &feedback_torque, &external_pause);
99100

100101
// Get required feedforward torque for current reference
101102
feedforward_torque = pbio_observer_get_feedforward_torque(srv->observer.model, ref.speed, ref.acceleration);

0 commit comments

Comments
 (0)