rcbench
Servo and ESC test bench: panel, IOmcu and shared C
Loading...
Searching...
No Matches
servo_limit.h File Reference

Finding a servo's installed mechanical limit by current. More...

#include <stdbool.h>
#include <stdint.h>

Go to the source code of this file.

Data Structures

struct  servo_limit_cfg_t
struct  servo_limit_t

Macros

#define SERVO_LIMIT_MIN_US   500u
 The pulse widths the search commands stay within, microseconds.
#define SERVO_LIMIT_MAX_US   2500u

Enumerations

enum  servo_limit_state_t { SERVO_LIMIT_RUNNING = 0 , SERVO_LIMIT_FOUND , SERVO_LIMIT_FAULT }
enum  servo_limit_fault_t {
  SERVO_LIMIT_FAULT_NONE = 0 , SERVO_LIMIT_FAULT_OVERCURRENT , SERVO_LIMIT_FAULT_STALL , SERVO_LIMIT_FAULT_NO_LIMIT ,
  SERVO_LIMIT_FAULT_BAD_CONFIG
}

Functions

void servo_limit_defaults (servo_limit_cfg_t *cfg, uint16_t centre_us, bool positive)
 Defaults for a hobby servo on a control surface.
void servo_limit_init (servo_limit_t *lf, const servo_limit_cfg_t *cfg)
 Start a limit search.
uint16_t servo_limit_step (servo_limit_t *lf, float current_a, uint32_t now_ms)
 Advance the search with one current reading, and return the pulse width the servo should be commanded to.
float servo_limit_progress (const servo_limit_t *lf)
 How far the search has gone, 0..1, for a progress bar.

Detailed Description

Finding a servo's installed mechanical limit by current.

A servo held against a mechanical stop draws stall current for as long as it is commanded there. The stop belongs to the linkage, the horn position and the surface stops, not to the servo, so it differs per installation and per end of travel and has to be measured in place.

The stop has a signature. While the surface is free, current against commanded position is flat and low. When the linkage binds, current rises steeply: the servo has stopped moving the surface and is pushing. The search walks out from centre in small steps, watches for the rise, stops at the first one rather than pushing through it, backs off by a margin, and reports that position as the endpoint.

The search drives toward a stop by design, so it carries three protections that need nothing from the panel:

  • a hard current ceiling that aborts immediately, wherever it is hit
  • a stall timeout on its own threshold, so current above the working level cannot persist, across positions as well as within one
  • a step small enough that one step cannot cross from free to bound

The search is a state machine fed measurements, not a loop that sleeps, so it runs on the host against a modelled servo. The IOmcu image does not call it yet; a real servo needs no change here.

SPDX-License-Identifier: MIT

Enumeration Type Documentation

◆ servo_limit_fault_t

Enumerator
SERVO_LIMIT_FAULT_OVERCURRENT 

Current crossed the hard ceiling.

The search stops where it stands.

SERVO_LIMIT_FAULT_STALL 

Current stayed above the knee for longer than the stall timeout.

SERVO_LIMIT_FAULT_NO_LIMIT 

The whole permitted travel was covered without binding.

Either the surface is free over that range or the sensor does not resolve the bind; reported as such rather than as a limit.

SERVO_LIMIT_FAULT_BAD_CONFIG 

step_us is 0: no step can reach a stop.

Set by servo_limit_init(), which then commands nothing but the centre.

Function Documentation

◆ servo_limit_defaults()

void servo_limit_defaults ( servo_limit_cfg_t * cfg,
uint16_t centre_us,
bool positive )

Defaults for a hobby servo on a control surface.

Parameters
cfgConfiguration to fill. Does nothing when NULL.
centre_usCentre pulse width, us.
positivetrue to step toward longer pulse widths, false toward shorter ones; the step is 10us either way.

◆ servo_limit_init()

void servo_limit_init ( servo_limit_t * lf,
const servo_limit_cfg_t * cfg )

Start a limit search.

Parameters
lfSearch state to initialise. Does nothing when NULL.
cfgConfiguration to copy. Does nothing when NULL.

◆ servo_limit_progress()

float servo_limit_progress ( const servo_limit_t * lf)

How far the search has gone, 0..1, for a progress bar.

Parameters
lfSearch state.
Returns
progress from 0.0 (centre) to 1.0; 1.0 when the state is not RUNNING, 0.0 when lf is NULL or max_travel_us is 0.

◆ servo_limit_step()

uint16_t servo_limit_step ( servo_limit_t * lf,
float current_a,
uint32_t now_ms )

Advance the search with one current reading, and return the pulse width the servo should be commanded to.

Call it at the sampling rate of the current sensor. Calling after the search has finished is safe; the returned width then holds the servo at centre, so a finished search leaves no surface deflected.

Parameters
lfSearch state. A NULL lf gives 0.
current_aCurrent reading, A. At or above hard_limit_a, or NaN, aborts the search.
now_msTime of the reading, ms.
Returns
pulse width to command, us; 0 when lf is NULL.