一、Simulink 的参数结构体

1.1 概述

对于 YuanHub 项目来说,每一个功能均由一个 Simulink 实现。

其 Simulink 仿真文件目录如下:

simulink_project/
├── simulink_project.prj        ← MATLAB 工程定义文件
├── architecture/               ← 系统架构模型
├── controller/                 ← 控制器模型(核心)
├── data/                       ← 模型数据字典
├── lib/                        ← Simulink 自定义库
├── module_code_gen/            ← 代码生成入口模型
├── plant/                      ← 被控对象(电机/传感器)模型
├── resources/                  ← MATLAB 工程资源/元数据
├── simulation/                 ← 独立仿真模型
├── test_harness/               ← 测试台架
├── utilities/                  ← 工具脚本
└── work/                       ← 工作/缓存目录

本文不关心别的文件夹,我们只讨论 controller/ 目录下的 Simulink 仿真文件:

controller/                       ← 控制器模型(核心)
├── csp_planning.slx              ← 同步位置模式 (CSP) 规划模型
├── cst_planning.slx              ← 同步力矩模式 (CST) 规划模型
├── csv_planning.slx              ← 同步速度模式 (CSV) 规划模型
├── current_ctl_loop_task.slx     ← 电流环控制任务模型
├── database_init.slx             ← 数据库/参数初始化模型
├── direction_id.slx              ← 电机方向辨识模型
├── elec_angle_id.slx             ← 电气角度/零位辨识模型
├── input_shaping_ei.slx          ← 输入整形 (Input Shaping) 滤波模型
├── linear_trajectory_planning.slx ← 线性轨迹规划模型
├── load_pos_sensor.slx           ← 负载端位置传感器处理模型
├── math_lib.slx                  ← 控制算法通用数学库
├── mit_ctl.slx                   ← MIT 力控模式模型
├── motor_ctl_sm.slx              ← 电机控制状态机模型
├── motor_pos_sensor.slx          ← 电机端位置传感器处理模型
├── notch_filter.slx              ← 陷波滤波器 (Notch Filter) 模型
├── notch_filter_config_set.slx   ← 陷波器配置参数设置模型
├── pole_pairs_id.slx             ← 电机极对数辨识模型
├── pos_speed_ctl_pip.slx         ← 位置/速度环 PI 控制器模型
├── pos_trajectory_planning.slx   ← 位置轨迹规划模型
├── protect_check.slx             ← 安全保护/故障检测模型
├── reciprocal_motion.slx         ← 往复运动控制模型
├── reference_signal.slx          ← 给定信号发生器模型
├── set_notch_filter_config.slx   ← 陷波器在线配置模型
├── speed_obs_pll.slx             ← 基于 PLL 的速度观测器模型
└── tq_fc_id.slx                  ← 扭矩/摩擦力辨识模型

在这个目录下的每一个 Simulink 仿真文件,均代表一个功能,它将被我们的 YuanHub 功能直接使用。

以电流环模型举例:

每一个模型均有 input、config 和 output 三个结构体,供每个独立模型使用。

在下文我们会举例几个较为常用的结构体,下面所有的结构体定义均在目录:

servo_hub-master\simulink_code_gen\servo_hub_database_type.h

1.2 总结构体

结构体 作用
Axis 顶层总结构体,包含下面所有子结构体,是整个控制层的数据接口
AxisDw 顶层内部工作状态(DW = Data Work),存放各模块的运行时中间变量

代码:

1.3 电机参数

结构体 作用
PmsmConfig PMSM 电机物理参数:极对数、电阻、电感 (Ld/Lq)、惯量、磁链、额定/峰值电流、最大转速、编码器分辨率、转矩常数、控制环周期等

代码:

1.4 电流环控制

1.4.1 模型外观

电流环的模型是:current_ctl_loop_task

我们可见每一个模型均有 input、config 和 output 三个结构体:

1.4.2 配置信息

其中输入输出和配置的结构体名分别为:

类型 结构体 作用
配置类 CurrentCtlConfig 电流环配置:PI 增益(kp/ki)、死区补偿电压、采样噪声、PWM 占空比上限、电角度补偿、UVW 相序方向
输入 CurrentCtlInput 电流环输入:目标 id/iq 电流、三相实测电流、电角度、母线电压、控制模式、驱动器温度、电角速度
输出 CurrentCtlOutput 电流环输出:补偿后目标三相电压 uabc、当前 dq 轴电流、补偿前目标三相电压

1.4.3 CurrentCtlConfig

typedef struct
{
    /* 电流采样噪声绝对值 */
    real32_T i_noise_A;

    /* 死区补偿电压大小 */
    real32_T comp_du_V;

    /* 电流环目标带宽 % */
    real32_T bandwidth_percentage;

    /* 电流环运行周期 */
    real32_T dt_s;

    /* 磁链系数 */
    real32_T flux_wb;

    /* d轴 kp控制增益 */
    real32_T kp_ld;

    /* d轴 ki控制增益 */
    real32_T ki_ld;

    /* q轴 kp控制增益 */
    real32_T kp_lq;

    /* q轴 ki控制增益 */
    real32_T ki_lq;

    /* pwm 占空比最大值 */
    real32_T pwm_duty_cycle_max;

    /* 电角度补偿系数 */
    real32_T elec_angle_compensation;

    /* UVW相序 */
    int8_T phase_dir;
}

CurrentCtlConfig;

1.4.4 CurrentCtlInput

typedef struct
{
    /* 目标id iq 电流 */
    real32_T idq_tar_A[2];

    /* iabc 三相当前电流反馈 */
    real32_T iabc_now_A[3];

    /* 当前电角度 */
    real32_T elec_theta_rad;

    /* 当前母线电压 */
    real32_T dc_bus_now_V;

    /* 电流环控制模式 */
    uint8_T mode;

    /* 三相目标电压 */
    real32_T uabc_tar_V[3];

    /* 驱动器当前温度 */
    real32_T driver_temp;

    /* 电角速度 */
    real32_T elec_angle_speed_rad_s;

    /* iq 目标电流偏置 */
    real32_T iq_offset_A;
}

CurrentCtlInput;

1.4.5 CurrentCtlOutput

typedef struct
{
    /* 死区补偿后目标三相电压 */
    real32_T uabc_tar_comp_V[3];

    /* 当前dq轴电流 */
    real32_T idq_now_A[2];

    /* 补偿前目标三相电压 */
    real32_T uabc_tar_org_V[3];
}

CurrentCtlOutput;

1.5 位置速度环控制

结构体 作用
配置类 PosSpeedCtlConfig 位置速度环配置:位置环 Kp、速度环 Kp/Ki、前馈系数(aff/vff)、惯性系数 J/Kt、运行周期、扰动观测器带宽及使能、动态积分使能
输入 PosSpeedCtlInput 位置速度环输入:目标位置、当前位置、目标速度、目标加速度、当前转速、最大 q 轴电流、位置/速度偏置
输出 PosSpeedCtlOutput 位置速度环输出:目标 q 轴电流、位置跟随误差、负载扰动补偿电流

1.6 电机编码器

结构体 作用
配置类 MotorPosSensorConfig 电机侧编码器配置:分辨率、初始位置、极对数、电角度偏移值、计数方向
输入 MotorPosSensorInput 电机侧编码器输入:当前单圈脉冲数
输出 MotorPosSensorOutput 电机侧编码器输出:累计脉冲值、当前电角度

1.7 速度观测器

结构体 作用
配置类 SpeedObsPllConfig PLL 速度观测器配置:运行周期、观测带宽、编码器分辨率倒数、最大速度限制
输入 SpeedObsPllInput 速度观测器输入:电机当前位置
输出 SpeedObsPllOutput 速度观测器输出:观测转速(rad/s)

1.8 错报与状态机

结构体 作用
配置类 MotorCtlSmConfig 控制状态机配置:运行模式、欠压/过压/过速/欠温/过温/过流/位置跟随误差保护阈值、保护使能位掩码
输入 MotorCtlSmInput 状态机输入:电机使能指令、硬件就绪状态
输出 MotorCtlSmOutput 状态机输出:运行状态(使能/失能/错误)、错误码、警告码、当前模式、上一周期状态

1.9 MIT 控制模式

结构体 作用
配置类 MitCtlConfig MIT 控制配置:位置刚度 Kp、速度阻尼 Kd、编码器分辨率倒数、转矩常数
输入 MitCtlInput MIT 控制输入:前馈力矩、目标/当前位置、目标/当前速度、最大 q 轴电流
输出 MitCtlOutput MIT 控制输出:目标 q 轴电流

1.10 其他

其他的结构体不再赘述

二、伺服本体参数数据库

2.1 概述

除 Simulink 所使用的参数之外,还有 YuanHub 所本身使用的全局变量。这也就是我们的参数数据库,或称对象字典。

其全部的结构定义在下目录中:

servo_hub-master\database\data_param.h

2.2 指令层

上位机/用户下发的控制指令

结构体 功能概述
AppControlWord 主控制字 + 运行中暂停命令,驱动状态机转换(使能/停机等)
AppOpMode 设定目标运行模式(PP/PV/PT/Homing/MIT 等)
AppMotionParam 各模式的运动目标值与轮廓参数(位置/速度/力矩目标、加减速、回零参数、MIT参数、插值时间等)
SystemCmd 系统级命令(复位/重启等)
EncoderCalibrationCmd 编码器校准控制字和校准时间

2.3 反馈层

设备实时状态上报

结构体 功能概述
AppStatusInfo 设备综合状态:状态字、错误字、告警字、母线电压、温度、功率、IO状态、抱闸、当前模式、版本
AppMotionInfo 运动实时数据:负载端/电机端的位置、速度、力矩、电流的指令值与反馈值,三相电流、控制环耗时/周期、回零状态等
SystemStatus 参数存储状态反馈 + Flash 存储命令
EncoderCalibrationStatus 编码器校准过程状态反馈
HistoricalInfo 16条历史错误记录,用于故障追溯

2.4 配置层

系统/硬件/保护参数

结构体 功能概述
AppEncoderConfig 编码器类型、分辨率、RPM⇔pps 及负载⇔电机端转换系数
AppBaseConfig 运动极性、回零偏移、CAN通信、快速停机、抱闸全套参数、数字IO输出
AppMotorConfig 电机物理参数:额定/峰值电流、力矩、极对数、转速、电阻/电感、减速比、惯量
AppProtectConfig 保护阈值:欠压/过压、过载/过流、过速、驱动器/电机/MCU温度报错与警告阈值、CAN超时
AppRestrictParam 运动安全限制:位置溢出/软件限位、速度/加速度/电流上限、限位使能
AppWindowParam 检测窗口:位置跟随误差、位置到达、速度到达、零速检测的窗口值与超时时间
AppPermissionConfig 控制权限:通信控制权限 / 内部控制权限切换
AppMavlinkConfig MAVLink 协议的系统ID和组件ID

2.5 辅助层

调试/标识/心跳

结构体 功能概述
HeartBit 系统初始化完成标志,用于启动握手/心跳检测
CustomInfo 用户模型编码,标识自定义模块
AppDebugParam 48个临时调试变量(16×float + 16×uint32 + 16×int32),供开发阶段使用

2.7 调试所常用的结构体

2.7.1 AppStatusInfo

typedef struct
{
    uint32_t Statusword; //状态字
    uint32_t Error_word; //错误字
    float DC_link_circuit_voltage; //母线电压当前值
    float Drive_accumulated_heat; //驱动器热量累计值
    float Drive_temperature; //驱动器当前温度
    uint32_t Alarm_word; //告警字
    int8_t Modes_of_operation_display; //当前模式
    uint32_t Version; //软件版本
    float Motor_temperature; //电机当前温度
    float Motor_power; //电机当前功率
    float Mcu_temperature; //Mcu当前温度
    uint32_t Digital_io_inputs_status; //数字IO输入状态
    uint8_t Brake_state; //抱闸状态
}AppStatusInfo;

2.7.2 AppMotionInfo

typedef struct
{
    int64_t Position_demand_value; //负载端位置指令值
    int64_t Position_actual_value_inc; //负载端内部位置当前值
    int64_t Position_actual_value; //负载端位置当前值
    int64_t Following_error_actual_value; //负载端位置误差值
    float Velocity_demand_value; //负载端速度指令值
    float Velocity_actual_value; //负载端速度当前值
    float Torque_demand_value; //力矩指令值
    float Torque_actual_value; //力矩当前值
    float Current_actual_value; //电流当前值
    float D_current_actual_value; //d轴电流当前值
    float U_current_actual_value; //U相当前电流
    float V_current_actual_value; //V相当前电流
    float W_current_actual_value; //W相当前电流
    int64_t Motor_position_demand_value; //电机端位置指令值
    int64_t Motor_position_actual_value; //电机端位置当前值
    int64_t Motor_following_error_actual_value; //电机端位置误差值
    float Motor_velocity_demand_value; //电机端速度指令值
    float Motor_velocity_actual_value; //电机端速度当前值
    uint16_t U_adc_mid_val; //U相电流校准值
    uint16_t V_adc_mid_val; //V相电流校准值
    uint16_t W_adc_mid_val; //W相电流校准值
    float Current_loop_time; //电流环耗时
    float Position_loop_time; //位置环耗时
    float Current_loop_cycle; //电流环周期
    float Position_loop_cycle; //位置环周期
    float Interp_period; //插值时间周期
    uint8_t Emergency_brake_requested; //紧急制动请求值
    uint8_t Target_update_state; //目标值更新状态
    int8_t Homing_step; //回零步骤
    uint8_t Encoder_zero_crossing_state; //编码器过零点状态
    int8_t Homing_state; //回零状态
}AppMotionInfo;

三、BspData 结构体

3.1 概述

kBspData 就是硬件层与控制算法层之间的数据桥梁——ADC 采样结果写进来,bsp_api.c 中的各种 bsp_get / bsp_set 函数读写它,控制环路(电流环、位置环)通过这些接口获取传感器数据并输出控制量。

3.2 结构与释义

typedef struct
{
    uint16_t adc1_raw_buffer[3];
    uint16_t adc2_raw_buffer[3];
    uint16_t adc3_raw_buffer[3];
    float dc_bus_voltage_val;
    float dc_bus_current_val;
    float motor_temp_val;
    float mos_temp_val;
    float mcu_temp[3];
    volatile float uvw_current[3];
    volatile float uvw_target_voltage[3];
    bool pwm_en_state;
    bool pwm_ready_state;
    uint32_t pwm_state_cnt;
    uint16_t brake_pwm_timer_psc;         // PWM抱闸IO输出定时器预分频值
    uint32_t brake_pwm_timer_arr;         // PWM抱闸IO输出定时器自动重装载值
    uint32_t brake_pwm_duty_ccr_tar;      // 抱闸PWM占空比对应CCR目标值
    uint32_t brake_pwm_duty_ccr_action;   // 抱闸PWM占空比对应CCR动作值
    uint32_t brake_pwm_duty_ccr_hold;     // 抱闸PWM占空比对应CCR保持值
    bool pl_start_state;
    BspCyclicSync cs;
} BspData;

含义如下:

成员变量 用途描述
adc1/2/3_raw_buffer[3] 3路 ADC 的 DMA 原始采样缓冲区(母线电压/电流、MOS温度、MCU温度等)
dc_bus_voltage_val 母线电压值 (V)
dc_bus_current_val 母线电流值 (A)
motor_temp_val / mos_temp_val / mcu_temp[3] 电机温度、MOS温度、MCU温度
uvw_current[3] UVW 三相实时电流 (A),volatile 修饰
uvw_target_voltage[3] UVW 三相目标电压 (V),volatile 修饰
pwm_en_state / pwm_ready_state / pwm_state_cnt PWM 使能状态、就绪状态及计数
brake_pwm_* 抱闸 PWM 控制参数(预分频、ARR、占空比CCR目标/动作/保持值)
pl_start_state 位置环是否已启动标志
cs (BspCyclicSync) EtherCAT 同步周期模式控制参数(DC/SM同步)

3.2 结构体内参数被赋值的过程

3.2.1 读取母线电压

/**
 * @brief 读取母线电压
 * @return float 母线电压,单位V
 */
float bsp_get_dc_bus_voltage(void)
{
#ifdef VIRTUAL_MOTOR_MODEL
    return kAxis.sim_plant_output.dc_bus_V;
#else
    kBspData.dc_bus_voltage_val = (float)kBspData.adc1_raw_buffer[DC_BUS_VOLTAGE_RANK1_INDEX] *
                                      DC_BUS_ADC_VOLTAGE_K +
                                  DC_BUS_ADC_VOLTAGE_BIAS;

    return kBspData.dc_bus_voltage_val;
#endif
}

3.2.2 读取母线电流

/**
 * @brief 读取母线电流
 * @return float 母线电流,单位A
 */
float bsp_get_dc_bus_current(void)
{
#ifdef VIRTUAL_MOTOR_MODEL
    return 0;
#else
    kBspData.dc_bus_current_val = (float)(kBspData.adc1_raw_buffer[DC_BUS_CURRENT_RANK2_INDEX] -
                                          UVW_CURRENT_MID_VAL) *
                                      DC_BUS_CURRENT_SAMP_ADC_K +
                                  DC_BUS_ADC_CURRENT_BIAS;

    return kBspData.dc_bus_current_val;
#endif
}

3.2.3 读取电机当前温度

/**
 * @brief 读取电机当前温度
 * @return float 电机温度,单位摄氏度
 */
float bsp_get_motor_temp(void)
{
#ifdef VIRTUAL_MOTOR_MODEL
    float temp = (float)(rand() % 201 - 100) / 10.0f;
    return 48.0f + temp;
#else
    kBspData.motor_temp_val = (float)kBspData.adc3_raw_buffer[TEMP_MOTOR_RANK2_INDEX] *
                                  MOTOR_TO_IN_VOLTAGE_RATIO * MOTOR_TEMP_SENSOR_K +
                              MOTOR_TEMP_SENSOR_BIAS;

    return kBspData.motor_temp_val;
#endif
}

3.2.4 读取 mos 当前温度

/**
 * @brief 读取mos当前温度
 * @return float mos温度,单位摄氏度
 */
float bsp_get_mos_temperature(void)
{
#ifdef VIRTUAL_MOTOR_MODEL
    return 25.0f;
#else
    float temp_mv = (float)kBspData.adc2_raw_buffer[TEMP_MOS_RANK1_INDEX] * MOS_TEMP_VOLTAGE_K;
    kBspData.mos_temp_val = (temp_mv - MOS_TEMP_SENSOR_BIAS) * MOS_TEMP_SENSOR_K;

    return kBspData.mos_temp_val;
#endif
}

3.2.5 读取 mcu 温度

/**
 * @brief 读取mcu温度
 * @return float 单位摄氏度
 * @note 底层提供三维数组,连续存放三个温度值,用于中值滤波
 */
float bsp_get_mcu_temperature(void)
{
    static uint8_t mcu_temp_index = 0;

    mcu_temp_index++;
    if (mcu_temp_index >= 3)
    {
        mcu_temp_index = 0;
    }
    kBspData.mcu_temp[mcu_temp_index] = __LL_ADC_CALC_TEMPERATURE(ADC_REFERENCE_MV,
                                                                  kBspData.adc3_raw_buffer[TEMP_MCU_RANK1_INDEX], LL_ADC_RESOLUTION_16B);

    return kBspData.mcu_temp[mcu_temp_index];
}

3.2.6 获取 UVW 三相电流

从 ADC 值计算出电流的公式如下:

K = (\frac{V_{ref}}{Resolution})\cdot \frac{1}{Gain}\cdot \frac{1}{R_{shunt}}

  • ADC = ADC 最大量程 (V)
  • Resolution = ADC 分辨率 (12位就是4096)
  • Gain = 放大倍数
  • Rshunt = 采样电阻值
  • K = 电流采样ADC转化系数

下面就是计算 K 的分辨率:

#define UVW_CURRENT_SAMP_ADC_K          (ADC_REFERENCE_V / ADC_RESOLTION /(CURRENT_SAMP_OPAMP_VOLTAGE_GAIN * UVW_CURRENT_SAMP_RES))   //UVW电流采样ADC转化系数

除此之外,还需要减去电流运放零点,全部代码如下:

/**
 * @brief 获取UVW三相电流
 * @param[out] piabc UVW三相电流数组,单位A
 */
void bsp_get_phase_current(float piabc[3])
{
#ifdef VIRTUAL_MOTOR_MODEL
    piabc[0] = kAxis.sim_plant_output.iabc_now_A[0];
    piabc[1] = kAxis.sim_plant_output.iabc_now_A[1];
    piabc[2] = kAxis.sim_plant_output.iabc_now_A[2];
#else
    uint16_t drift[3] = {0};

    if (false == bsp_get_pwm_state()) // PWM未准备好,电流采样回读值强制为0
    {
        kBspData.uvw_current[0] = 0.0f;
        kBspData.uvw_current[1] = 0.0f;
        kBspData.uvw_current[2] = 0.0f;
    }
    else
    {
        sys_get_current_calibration_drift(drift);

        kBspData.uvw_current[0] = UVW_CURRENT_DIRECTION *
                                  (float)(int32_t)(UVW_CURRENT_U_CHANNEL - drift[0]) * UVW_CURRENT_SAMP_ADC_K;
        kBspData.uvw_current[1] = UVW_CURRENT_DIRECTION *
                                  (float)(int32_t)(UVW_CURRENT_V_CHANNEL - drift[1]) * UVW_CURRENT_SAMP_ADC_K;
        kBspData.uvw_current[2] = UVW_CURRENT_DIRECTION *
                                  (float)(int32_t)(UVW_CURRENT_W_CHANNEL - drift[2]) * UVW_CURRENT_SAMP_ADC_K;
    }

    piabc[0] = kBspData.uvw_current[0];
    piabc[1] = kBspData.uvw_current[1];
    piabc[2] = kBspData.uvw_current[2];
#endif
}
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐