|
rcbench
Servo and ESC test bench: panel, IOmcu and shared C
|
One servo move judged from the servo's current, sample by sample: when it started moving and when it arrived, from a step command to one end. More...
#include <stdbool.h>#include <stdint.h>Go to the source code of this file.
Data Structures | |
| struct | servo_move_cfg_t |
| struct | servo_move_t |
Macros | |
| #define | SERVO_MOVE_MIN_A 0.020f |
| The smallest threshold. | |
| #define | SERVO_MOVE_NOISE_K 3.0f |
| The threshold in idle noises, where that is larger. | |
| #define | SERVO_MOVE_BAND_A 0.05f |
| Back within this of the holding level, and not above it by the threshold, is the move arrived. | |
| #define | SERVO_MOVE_TIMEOUT_MS 3000u |
| A move not arrived this long after its command is late, or unseen; a meter's lag is added (servo_move_window_ms()). | |
| #define | SERVO_MOVE_FILTER_MAX 8u |
| The longest filter. | |
Enumerations | |
| enum | servo_move_state_t { SERVO_MOVE_IDLE = 0 , SERVO_MOVE_WAITING , SERVO_MOVE_MOVING , SERVO_MOVE_ARRIVED , SERVO_MOVE_SETTLED , SERVO_MOVE_LATE , SERVO_MOVE_UNSEEN } |
| Where a move stands. More... | |
| enum | servo_move_clip_t { SERVO_MOVE_CLIP_LOW = -1 , SERVO_MOVE_CLIP_NONE = 0 , SERVO_MOVE_CLIP_HIGH = 1 } |
| A sample at the end of the meter's range. More... | |
Functions | |
| float | servo_move_noise_a (uint32_t n, float sum, float sum_sq) |
The standard deviation of n samples given as their sum and the sum of their squares; 0 for none. | |
| float | servo_move_threshold_a (float noise_a) |
The threshold for a noise at rest of noise_a. | |
| uint32_t | servo_move_window_ms (uint32_t lag_ms) |
SERVO_MOVE_TIMEOUT_MS plus a meter's lag of lag_ms. | |
| void | servo_move_begin (servo_move_t *m, const servo_move_cfg_t *cfg) |
| A move begins: commanded at cfg->cmd_t, from cfg->rise_a towards cfg->ref_a. settle_n below 2 is taken as 2; filter_n is held to 1 to SERVO_MOVE_FILTER_MAX. | |
| void | servo_move_prime (servo_move_t *m, float a, servo_move_clip_t clip) |
| A sample taken before the move began, into the filter only, as the newest so far: a caller that held samples before it knew the command's time hands them over oldest first. Decides nothing; nothing with filter_n 1 or once the move is over. | |
| servo_move_state_t | servo_move_sample (servo_move_t *m, uint32_t at, float a, servo_move_clip_t clip) |
A sample taken at at: a amps, or for a clip the end of the range it is at or past. | |
| servo_move_state_t | servo_move_tick (servo_move_t *m, uint32_t now) |
The time is now: a move still under way at window_t after its command is over, late or unseen, with end_t at now. A now before the command decides nothing. | |
| bool | servo_move_over (const servo_move_t *m) |
| Whether the move is over: arrived, settled, late or unseen. | |
| bool | servo_move_arrived (const servo_move_t *m) |
| Whether the move arrived: ARRIVED or SETTLED. | |
| bool | servo_move_moved (const servo_move_t *m) |
| Whether movement was seen. | |
One servo move judged from the servo's current, sample by sample: when it started moving and when it arrived, from a step command to one end.
Nothing measures the horn. Current rises while the motor drives and falls back to the holding level as it stops, which can lead or lag the horn's arrival. The rules:
Threshold the larger of SERVO_MOVE_MIN_A and SERVO_MOVE_NOISE_K times the noise at rest, the standard deviation of the idle samples (servo_move_noise_a(), servo_move_threshold_a()). Movement the first sample more than the threshold away from the level before the command: above it, or below it when the servo leaves an end it was pushing on. Arrival after movement, a sample more than the threshold above the destination's holding level, then the first sample back within the band of it, on either side. A sample above the level by the threshold is never an arrival, so a band wider than the threshold times no move early. A sample more than the band below the level instead hands the move to the settled rule. Settled an end held harder than the servo moves, an end pushing on a stop, is never passed: there the move has arrived at the first of settle_n samples in a row, after movement, within the band of the level and of each other (the highest less the lowest at most the band). Window a move not arrived window_t after its command is over: late with movement seen, unseen without. servo_move_window_ms() adds the meter's lag to SERVO_MOVE_TIMEOUT_MS, since its samples show an arrival that much later. A sample at or past the window's end ends the move there and is never its arrival.
The same rules run at two rates. The panel's servo test feeds the PD mini's readings, about 10 a second, with time in ms, settle_n 2 and no filter. The IOmcu feeds INA3221 CH1 samples at 1kHz with time in 0.1ms (sense_sched.h). The time unit is the caller's: cmd_t, window_t and every sample's time are in it.
Filter. With filter_n above 1 each sample is judged as the mean of the last filter_n samples, those before the command included; the filtered sample carries the newest sample's time; a step shows half after (filter_n - 1) / 2 samples and whole after filter_n - 1. With filter_n 1 a sample is judged as it is. Samples held from before the move began go in with servo_move_prime().
Clipping. A sample at the end of the meter's range carries no value: it is at or past a, by how much is not known. It decides only what that bound decides – movement when the bound lies more than the threshold from the level before the command, not yet there when the bound lies more than the threshold above the destination's level – and is never an arrival. It adds nothing to the mean and the peak, and marks them clipped. A filtered sample with a clipped sample in its window is clipped the same way; one with both ends clipped in its window decides nothing.
SPDX-License-Identifier: MIT
| #define SERVO_MOVE_MIN_A 0.020f |
The smallest threshold.
A sample more than the threshold from the level before a command is the servo moving, and more than it above an end's holding level is the move not yet there.
| enum servo_move_clip_t |
| enum servo_move_state_t |
Where a move stands.
| bool servo_move_arrived | ( | const servo_move_t * | m | ) |
Whether the move arrived: ARRIVED or SETTLED.
| m | Move state. |
| void servo_move_begin | ( | servo_move_t * | m, |
| const servo_move_cfg_t * | cfg ) |
A move begins: commanded at cfg->cmd_t, from cfg->rise_a towards cfg->ref_a. settle_n below 2 is taken as 2; filter_n is held to 1 to SERVO_MOVE_FILTER_MAX.
| m | Move state to initialise. |
| cfg | Configuration of the move. |
| bool servo_move_moved | ( | const servo_move_t * | m | ) |
Whether movement was seen.
| m | Move state. |
| float servo_move_noise_a | ( | uint32_t | n, |
| float | sum, | ||
| float | sum_sq ) |
The standard deviation of n samples given as their sum and the sum of their squares; 0 for none.
| n | Number of samples. |
| sum | Sum of the samples, A. |
| sum_sq | Sum of the squares of the samples, A^2. |
| bool servo_move_over | ( | const servo_move_t * | m | ) |
Whether the move is over: arrived, settled, late or unseen.
| m | Move state. |
| void servo_move_prime | ( | servo_move_t * | m, |
| float | a, | ||
| servo_move_clip_t | clip ) |
A sample taken before the move began, into the filter only, as the newest so far: a caller that held samples before it knew the command's time hands them over oldest first. Decides nothing; nothing with filter_n 1 or once the move is over.
| m | Move state. |
| a | Sample, A. |
| clip | Clip state of the sample. |
| servo_move_state_t servo_move_sample | ( | servo_move_t * | m, |
| uint32_t | at, | ||
| float | a, | ||
| servo_move_clip_t | clip ) |
A sample taken at at: a amps, or for a clip the end of the range it is at or past.
A sample taken before the command only fills the filter; one at or past window_t after the command ends the move late or unseen, as servo_move_tick() would, and is not judged. Returns the state after it; ARRIVED and SETTLED leave end_t at the arrival. Nothing once the move is over.
| m | Move state. |
| at | Time of the sample, in the caller time unit. |
| a | Sample, A. |
| clip | SERVO_MOVE_CLIP_NONE for a sample; SERVO_MOVE_CLIP_LOW or SERVO_MOVE_CLIP_HIGH when the reading is at the end of its range. |
| float servo_move_threshold_a | ( | float | noise_a | ) |
The threshold for a noise at rest of noise_a.
| noise_a | Noise at rest, A. |
| servo_move_state_t servo_move_tick | ( | servo_move_t * | m, |
| uint32_t | now ) |
The time is now: a move still under way at window_t after its command is over, late or unseen, with end_t at now. A now before the command decides nothing.
| m | Move state. |
| now | Current time, in the caller time unit. |
| uint32_t servo_move_window_ms | ( | uint32_t | lag_ms | ) |
SERVO_MOVE_TIMEOUT_MS plus a meter's lag of lag_ms.
| lag_ms | Lag of the meter readings, ms. |