Skip to content

File syn_actuator.c

File List > motor > syn_actuator.c

Go to the documentation of this file

#if __has_include("syn_config.h")
#include "syn_config.h"
#endif

#if !defined(SYN_USE_ACTUATOR) || SYN_USE_ACTUATOR

#include "../motor/syn_dc_motor.h"
#include "../util/syn_assert.h"
#include "syn_actuator.h"

#include <string.h>

/* ── Helpers ────────────────────────────────────────────────────────────── */

static int32_t pct_to_adc(const SYN_Actuator *act, int16_t pct)
{
    return act->stroke_min + ((int32_t)pct * act->stroke_range) / 1000;
}

static int16_t adc_to_pct(const SYN_Actuator *act, int32_t adc)
{
    if (act == NULL || act->stroke_range == 0)
        return 0;

    int32_t pct = ((adc - act->stroke_min) * 1000) / act->stroke_range;
    return (int16_t)SYN_CLAMP(pct, 0, 1000);
}

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

void syn_actuator_init(SYN_Actuator *act, const SYN_Actuator_Config *cfg)
{
    SYN_ASSERT(act != NULL);
    SYN_ASSERT(cfg != NULL);
    SYN_ASSERT(cfg->dc_motor != NULL);
    SYN_ASSERT(cfg->read_pos != NULL);

    memset(act, 0, sizeof(*act));
    act->stroke_min = cfg->stroke_min;
    act->stroke_max = cfg->stroke_max;
    act->stroke_range = cfg->stroke_max - cfg->stroke_min;

    /* Configure underlying motor controller */
    SYN_MotorCtrl_Config mc;
    memset(&mc, 0, sizeof(mc));
    mc.motor = syn_dc_motor_output(cfg->dc_motor);
    mc.read_pos = cfg->read_pos;
    mc.read_pos_ctx = cfg->read_ctx;
    mc.update_hz = cfg->update_hz;
    mc.pid_kp = cfg->pid_kp > 0 ? cfg->pid_kp : 100;
    mc.pid_ki = cfg->pid_ki;
    mc.pid_kd = cfg->pid_kd;
    mc.pid_scale = cfg->pid_scale;
    mc.position_deadband = cfg->deadband;
    mc.output_min = -cfg->dc_motor->duty_max;
    mc.output_max = cfg->dc_motor->duty_max;
    mc.position_min = cfg->stroke_min;
    mc.position_max = cfg->stroke_max;
    mc.stall_timeout_ms = cfg->stall_timeout_ms;
    mc.stall_threshold = cfg->stall_threshold;
    mc.errlog = cfg->errlog;

    syn_motor_ctrl_init(&act->ctrl, &mc);

    /* Read initial position */
    int32_t pos = cfg->read_pos(cfg->read_ctx);
    act->current_pct = adc_to_pct(act, pos);
    act->target_pct = act->current_pct;
}

void syn_actuator_set_position(SYN_Actuator *act, int16_t pct_x10)
{
    SYN_ASSERT(act != NULL);

    if (pct_x10 < 0)
        pct_x10 = 0;
    if (pct_x10 > 1000)
        pct_x10 = 1000;

    act->target_pct = pct_x10;

    int32_t target_adc = pct_to_adc(act, pct_x10);
    syn_motor_ctrl_set_position(&act->ctrl, target_adc);
}

int16_t syn_actuator_update(SYN_Actuator *act)
{
    SYN_ASSERT(act != NULL);

    syn_motor_ctrl_update(&act->ctrl);
    act->current_pct = adc_to_pct(act, act->ctrl.measured_position);

    return act->current_pct;
}

void syn_actuator_stop(SYN_Actuator *act)
{
    SYN_ASSERT(act != NULL);
    syn_motor_ctrl_stop(&act->ctrl);
    act->target_pct = act->current_pct;
}

void syn_actuator_clear_stall(SYN_Actuator *act)
{
    SYN_ASSERT(act != NULL);
    syn_motor_ctrl_clear_stall(&act->ctrl);
}

#endif /* SYN_USE_ACTUATOR */