Skip to content

File syn_autotune.h

File List > control > syn_autotune.h

Go to the documentation of this file

#ifndef SYN_AUTOTUNE_H
#define SYN_AUTOTUNE_H

#include "../common/syn_defs.h"
#include "../motor/syn_motor_ctrl.h"

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

#ifdef __cplusplus
extern "C" {
#endif

/* ── Mode ──────────────────────────────────────────────────────────────── */

typedef enum {
    SYN_ATUNE_MODE_FF_IDENT = 0, 
    SYN_ATUNE_MODE_RELAY = 1,    
    SYN_ATUNE_MODE_AUTO = 2,     
} SYN_AutoTune_Mode;

/* ── PID formula ───────────────────────────────────────────────────────── */

typedef enum {
    SYN_ATUNE_ZN_CLASSIC = 0,      
    SYN_ATUNE_ZN_NO_OVERSHOOT = 1, 
    SYN_ATUNE_TYREUS_LUYBEN = 2,   
} SYN_AutoTune_Method;

/* ── State ─────────────────────────────────────────────────────────────── */

typedef enum {
    SYN_ATUNE_IDLE,
    SYN_ATUNE_PROBE,
    SYN_ATUNE_RAMP_UP,
    SYN_ATUNE_SETTLING,
    SYN_ATUNE_MEASURING,
    SYN_ATUNE_SETTLING_2,
    SYN_ATUNE_MEASURING_2,
    SYN_ATUNE_RELAY,
    SYN_ATUNE_BRAKING,
    SYN_ATUNE_RAMP_DOWN,
    SYN_ATUNE_DONE,
    SYN_ATUNE_ABORTED
} SYN_AutoTune_State;

typedef enum {
    SYN_ATUNE_FLAG_NONE = 0,
    SYN_ATUNE_FLAG_IDENT_KV = (1 << 0), 
    SYN_ATUNE_FLAG_IDENT_KA = (1 << 1), 
    SYN_ATUNE_FLAG_TUNE_PID = (1 << 2), 
    SYN_ATUNE_FLAG_ALL =
        (SYN_ATUNE_FLAG_IDENT_KV | SYN_ATUNE_FLAG_IDENT_KA | SYN_ATUNE_FLAG_TUNE_PID)
} SYN_AutoTune_Flags;

/* ── Abort reason ──────────────────────────────────────────────────────── */

typedef enum {
    SYN_ATUNE_OK = 0,               
    SYN_ATUNE_ABORT_POSITION = 1,   
    SYN_ATUNE_ABORT_VELOCITY = 2,   
    SYN_ATUNE_ABORT_SOFT_LIMIT = 3, 
    SYN_ATUNE_ABORT_WATCHDOG = 4,   
    SYN_ATUNE_ABORT_USER = 5,       
    SYN_ATUNE_ABORT_STALL = 6,      
    SYN_ATUNE_ABORT_NO_MOTION = 7,  
} SYN_AutoTune_AbortReason;

#define SYN_ATUNE_LOG_ID 0x4154 /* 'AT' */

typedef struct {
    uint8_t state;    
    int16_t output;   
    int32_t position; 
    int32_t velocity; 
} SYN_AutoTune_LogFrame;

typedef struct {
    int32_t position_min; 
    int32_t position_max; 
    int32_t max_velocity; 
    uint32_t watchdog_ms; 
} SYN_AutoTune_Limits;

/* ── Configuration ─────────────────────────────────────────────────────── */

typedef struct {
    SYN_AutoTune_Mode mode; 
    int32_t test_output;

    /* FF identification timing */
    uint32_t settle_ms;  
    uint32_t measure_ms; 
    /* Relay feedback config */
    int32_t setpoint;           
    uint8_t relay_cycles;       
    SYN_AutoTune_Method method; 
    /* Telemetry (optional) */
    SYN_DataLog *datalog; 
    SYN_AutoTune_Flags flags; 
    /* ── Safety (all mandatory for heavy machinery) ─────────────── */
    SYN_AutoTune_Limits limits; 
    uint32_t watchdog_ms;

    uint32_t ramp_ms;

    uint16_t gain_multiplier_pct;
} SYN_AutoTune_Config;

/* ── Result ────────────────────────────────────────────────────────────── */

typedef struct {
    /* Feedforward identification results */
    int32_t ff_kv;             
    int32_t ff_ka;             
    uint8_t ff_scale;          
    int32_t steady_velocity_1; 
    int32_t steady_velocity_2; 
    /* Relay feedback results */
    int32_t Ku;        
    uint32_t Tu_ms;    
    int32_t kp;        
    int32_t ki;        
    int32_t kd;        
    uint8_t pid_scale; 
} SYN_AutoTune_Result;

/* ── Auto-tuner instance ───────────────────────────────────────────────── */

typedef struct {
    SYN_AutoTune_Config cfg;               
    SYN_AutoTune_Result result;            
    SYN_AutoTune_State state;              
    SYN_AutoTune_AbortReason abort_reason; 
    SYN_MotorCtrl *ctrl; 
    /* Internal state */
    int32_t start_position;    
    uint32_t phase_start_tick; 
    uint32_t last_update_tick; 
    int32_t current_output;    
    int32_t start_output;      
    /* Steady-state monitoring */
    int32_t history_v;        
    uint32_t last_check_tick; 
    /* FF ident internals */
    int64_t velocity_sum;      
    uint32_t velocity_samples; 
    int32_t ka_v1;             
    int32_t ka_v2;             
    uint32_t ka_t1;            
    uint32_t ka_t2;            
    bool ka_p1_captured;       
    bool ka_p2_captured;       
    /* Oscillation tracking */
    int32_t relay_output;     
    uint8_t half_cycles;      
    uint32_t last_cross_tick; 
    uint32_t period_sum;      
    uint8_t period_count;     
    int32_t osc_peak_pos;     
    int32_t osc_peak_neg;     
    int32_t amplitude_sum;    
    uint8_t amplitude_count;  
    bool above_setpoint;      
} SYN_AutoTune;

/* ── API ───────────────────────────────────────────────────────────────── */

SYN_Status syn_autotune_init(SYN_AutoTune *at, SYN_MotorCtrl *ctrl, const SYN_AutoTune_Config *cfg);

SYN_AutoTune_State syn_autotune_update(SYN_AutoTune *at);

static inline const SYN_AutoTune_Result *syn_autotune_result(const SYN_AutoTune *at)
{
    return &at->result;
}

static inline SYN_AutoTune_AbortReason syn_autotune_abort_reason(const SYN_AutoTune *at)
{
    return at->abort_reason;
}

void syn_autotune_apply(SYN_AutoTune *at);

void syn_autotune_abort(SYN_AutoTune *at);

/* ── One-call auto-tune API ────────────────────────────────────────────── */

SYN_Status syn_autotune_start(SYN_AutoTune *at, SYN_MotorCtrl *ctrl,
                              const SYN_AutoTune_Limits *limits, SYN_AutoTune_Flags flags,
                              uint16_t gain_multiplier);

void syn_autotune_calc_relay_gains(int32_t Ku, uint32_t Tu_ms, SYN_AutoTune_Method method,
                                   uint16_t multiplier_pct, int32_t *kp, int32_t *ki, int32_t *kd);

#ifdef __cplusplus
}
#endif

#endif /* SYN_AUTOTUNE_H */