@@ -154,15 +154,32 @@ void pbio_control_update(pbio_control_t *ctl, int32_t time_now, pbio_control_sta
154154 // If on target, decide what to do next using the on-completion type.
155155 switch (ctl -> on_completion ) {
156156 case PBIO_CONTROL_ON_COMPLETION_COAST :
157+ // Coast the motor and stop the control loop.
157158 * actuation = PBIO_DCMOTOR_ACTUATION_COAST ;
158159 * control = 0 ;
159160 pbio_control_stop (ctl );
160161 break ;
161162 case PBIO_CONTROL_ON_COMPLETION_BRAKE :
163+ // Passively brake and stop the control loop.
162164 * actuation = PBIO_DCMOTOR_ACTUATION_BRAKE ;
163165 * control = 0 ;
164166 pbio_control_stop (ctl );
165167 break ;
168+ case PBIO_CONTROL_ON_COMPLETION_COAST_SMART :
169+ // For smart coast, keep actuating (holding) briefly to enforce
170+ // standstill. It also gives some time for two subsequent
171+ // blocks to smoothly transition without going through coast.
172+ if (time_ref - ctl -> trajectory .t3 < 100 * US_PER_MS ) {
173+ * actuation = PBIO_DCMOTOR_ACTUATION_TORQUE ;
174+ * control = torque ;
175+ }
176+ // After that, coast the motor and stop the control loop.
177+ else {
178+ * actuation = PBIO_DCMOTOR_ACTUATION_COAST ;
179+ * control = 0 ;
180+ pbio_control_stop (ctl );
181+ }
182+ break ;
166183 case PBIO_CONTROL_ON_COMPLETION_CONTINUE :
167184 // Fall through, same as hold.
168185 case PBIO_CONTROL_ON_COMPLETION_HOLD :
@@ -298,19 +315,34 @@ pbio_error_t pbio_control_start_angle_control(pbio_control_t *ctl, int32_t time_
298315
299316pbio_error_t pbio_control_start_relative_angle_control (pbio_control_t * ctl , int32_t time_now , pbio_control_state_t * state , int32_t relative_target_count , int32_t target_rate , pbio_control_on_completion_t on_completion ) {
300317
301- // Get the count from which the relative count is to be counted
318+ // First, we need to decide where the relative motion starts from.
302319 int32_t count_start ;
303320
304- // If no control is active, count from the physical count
305- if (!pbio_control_is_active (ctl )) {
306- count_start = state -> count ;
307- }
308- // Otherwise count from the current reference
309- else {
321+ if (pbio_control_is_active (ctl )) {
322+ // If control is already active, restart from current reference.
310323 int32_t time_ref = pbio_control_get_ref_time (ctl , time_now );
311324 pbio_trajectory_reference_t ref ;
312325 pbio_trajectory_get_reference (& ctl -> trajectory , time_ref , & ref );
313326 count_start = ref .count ;
327+ } else {
328+ // Control is inactive. We still have two options.
329+ // If the previous command used smart coast and we're still close to
330+ // its target, we want to start from there. This avoids accumulating
331+ // errors in programs that use mostly relative motions like run_angle.
332+ if (ctl -> on_completion == PBIO_CONTROL_ON_COMPLETION_COAST_SMART &&
333+ abs (ctl -> trajectory .th3 - state -> count ) < ctl -> settings .count_tolerance * 2 ) {
334+ // We're close enough, so make the new target relative to the
335+ // endpoint of the last one.
336+ count_start = ctl -> trajectory .th3 ;
337+
338+ // FIXME: We need to clear the on-completion state between program
339+ // to make each program run independent.
340+
341+ } else {
342+ // No special cases apply, so the best we can do is just start from
343+ // the current state.
344+ count_start = state -> count ;
345+ }
314346 }
315347
316348 // The target count is the start count plus the count to be traveled. If speed is negative, traveled count also flips.
@@ -360,6 +392,11 @@ pbio_error_t pbio_control_start_timed_control(pbio_control_t *ctl, int32_t time_
360392
361393 pbio_error_t err ;
362394
395+ if (on_completion == PBIO_CONTROL_ON_COMPLETION_COAST_SMART ) {
396+ // For timed maneuvers, the end point has no meaning, so just coast.
397+ on_completion = PBIO_CONTROL_ON_COMPLETION_COAST ;
398+ }
399+
363400 // Set new maneuver action and stop type, and state
364401 ctl -> on_completion = on_completion ;
365402 ctl -> on_target = false;
0 commit comments