资讯详情

资讯详情

基于TMS320F28335的永磁同步电机FOC控制完整工程实现

简介围绕基于TMS320F28335的电机FOC控制整理的一份工程源码包面向电机驱动、嵌入式控制领域的开发人员和学生解决磁场定向控制与SVPWM调制在DSP平台上的落地实现问题。资源共135个文件压缩包1.25MB核心以33个h、25个c源文件构成另有asm启动及中断例程、lib库、cmd链接脚本和gel调试配置文件可配合CCS环境直接导入便于学习与二次开发。已有2211人学习下载。包内提供Main.c、DSP2833x_DefaultIsr.c等关键代码覆盖传感器数据采集、Clarke/Park坐标变换、d/q轴PI控制器设计以及SVPWM脉冲生成环节同时带有DSP2833x标准外设库与调试配置文件能帮助读者理解FOC完整控制流程并根据实际电机参数调整适配。整体工程结构清晰兼顾原理讲解与工程应用适合用作电机控制入门与进阶的参考资料。1. 为什么 28335 的 FOC 是工程问题不只是算法问题很多人第一眼看到“基于 28335 的电机 FOC 控制”这个标题会默认难点在坐标变换的数学推导上。实际拆完这套代码你会发现Clarke、Park、SVPWM 的公式只占很小一块面积真正让电机稳定转起来的是 ADC 采样时序和 ePWM 载波的对齐、编码器电角度的初始对准、电流环 PI 参数的估算这些工程细节。它是一套完整的永磁同步电机矢量控制落地工程覆盖相电流采样、坐标变换、双电流环控制到 SVPWM 生成 PWM 波形的完整链路适合做伺服驱动、机器人和电动工具的开发者拿来当平台起点。这套代码的运行平台是 TMS320F28335一颗带硬件浮点单元的 DSP跑 10kHz 电流环绰绰有余还有专门为电机控制设计的片上外设这也是它在电机控制领域长期被选用的原因。2. 平台与工程结构为什么 28335 适合做 FOC2.1 选 28335 的三个硬理由先看芯片本身的竞争力。FOC 控制环路上全是浮点运算坐标变换、PI 输出、SVPWM 计算每一步都有小数运算。28335 是 C2000 系列里较早带单精度硬件浮点单元FPU的型号主频能做到 150MHz写代码的时候直接用 float 声明变量编译器翻译成浮点指令一条条执行不用像老一代 C28x 那样手动做 Q 格式定点换算。这一点对开发效率的提升非常大我见过不少从定点 DSP 转过来的工程师头一次在这颗芯片上写 FOC被 IDF 数学库省掉的几百行救回来。其次电机控制需要的外设它基本都集成了。三个 ePWM 模块可以产生三相六路 PWM自带死区生成单元不用外部逻辑芯片插死区ADC 模块可以被 ePWM 硬件触发做到与 PWM 载波严格同步的电流采样正交编码器接口EQEP直接接增量编码器的 A、B、Z 信号四倍频计数由硬件完成。也就是说从采样到输出 PWM 的整条通路都不需要 CPU 实时干预CPU 只负责在每个载波周期里跑一遍 FOC 算法。最后是中断响应能力。28335 的 PIE 中断控制器支持外设中断的快速响应和嵌套ePWM 周期中断触发电流环中断进入后直接读 ADC 结果、跑坐标变换和 PI、更新比较寄存器整个过程可以控制在十几微秒以内。10kHz 的电流环在它上面属于比较常规的负载。2.2 硬件拓扑三相逆变、电流采样与编码器反馈整套系统的硬件拓扑是标准的 FOC 驱动结构。直流母线电压经过三相全桥逆变器一般用 IPM 智能功率模块给电机供电IPM 内部集成 IGBT 和驱动电路28335 的 ePWM 输出经过六路缓冲后直接进 IPM 的输入引脚。母线电压通过电阻分压采样送入 ADC 的其中一个通道用于电压前馈和过压保护。相电流采样有两种常见方式双电阻采样和单电阻采样。这套工程里用的是双电阻方案在逆变器下桥臂串联采样电阻分别采 U、V 两相的电流W 相电流由基尔霍夫定律计算得到。采样电阻上的电压经过运放放大和偏置处理后送 ADC 引脚因为电流有正有负运放会把信号抬升到 ADC 输入范围的中间值附近代码里要做偏移校准。转子位置反馈用的是增量式编码器A、B 两路正交信号接 EQEP 模块Z 信号用于每转一圈的零点校准。编码器线数常见的是 2500 线四倍频后每圈 10000 个脉冲对应 0.036 度的机械角度分辨率对于 FOC 的电流环控制来说足够。因为没有绝对位置上电后需要先做一次转子预定位让转子转到已知电角度这个细节后面单独讲。2.3 工程目录与模块划分这套工程的文件组织我拆完是这么个结构也符合一般的 28335 DSP 项目习惯28335_foc/ ├── src/ │ ├── main.c // 系统初始化、主循环 │ ├── foc.c // FOC 主流程电流环状态机 │ ├── svpwm.c // SVPWM 扇区判断与占空比计算 │ ├── pid.c // 位置式 PID 控制器 │ ├── encoder.c // EQEP 初始化和转子角度解算 │ ├── adc_drv.c // ADC 初始化、结果读取与偏移校准 │ └── pwm_drv.c // ePWM 初始化、死区配置、PWM 更新 ├── include/ │ ├── foc.h │ ├── svpwm.h │ ├── pid.h │ └── motor_cfg.h // 电机参数、极对数、编码器线数 ├── debug/ │ └── 28335_foc.out └── linker.cmd // DSP 内存分配脚本foc.c 是核心里面管 FOC 的运行状态motor_cfg.h 里放电机参数和控制参数换电机时只需改这个头文件。pid.c 独立出来是为了同时被电流环和速度环复用后面加转速环不需要重写。linker.cmd 是 DSP 的内存分配脚本如果要把代码跑在 RAM 里获得更高速度也需要在这里面做段分配。3. 核心算法实现电流采样到 SVPWM 的完整链路3.1 电流采样与坐标变换Clarke 和 Park 的实现FOC 的第一步是把三相定子电流变换到转子同步旋转坐标系让电流控制变得像直流电机控制一样直观。先做 Clarke 变换把三相电流从 U、V、W 轴系变换到静止的 α、β 轴系再做 Park 变换把 α、β 轴系的电流变换到随转子旋转的 d、q 轴系。typedef struct { float i_alpha; float i_beta; } clark_out_t; clark_out_t clark_transform(float ia, float ib) { clark_out_t out; /* 三相平衡时 ic -ia - ib省掉一路 ADC */ float ic -ia - ib; out.i_alpha ia; /* 1.0f / 1.73205f等幅值变换系数 */ out.i_beta (ia 2.0f * ib) * 0.57735f; (void)ic; return out; }等幅值变换的好处是变换后的 α、β 轴幅值与实际相电压幅值一致后面 SVPWM 的调制深度计算可以直接用电压值做比较不需要额外换算。i_beta 的系数来自矩阵推导等幅值变换下 Clarke 矩阵第二行是 1/√3 乘以 [1, 2, 0] 的组合。typedef struct { float id; float iq; } park_out_t; park_out_t park_transform(float i_alpha, float i_beta, float theta) { park_out_t out; float cos_t cosf(theta); float sin_t sinf(theta); /* d 轴对齐转子磁极方向q 轴超前 90° 电角度 */ out.id i_alpha * cos_t i_beta * sin_t; out.iq -i_alpha * sin_t i_beta * cos_t; return out; }这里的关键是 theta 必须是电角度不是编码器测出来的机械角度。电角度等于机械角度乘以电机极对数如果电机是 4 对极编码器转一圈电角度已经转了四圈。这个乘关系如果漏掉FOC 直接失效电流环输出会乱跳。3.2 电流环 PI 控制器限幅和积分饱和处理电流环用位置式 PIDd 轴电流环和 q 轴电流环各一个实例。FOC 里常用 PI 而非完整 PID因为微分项会放大电流采样噪声。代码里我保留了 kd 字段但默认设为 0想测试微分效果时可以直接调。typedef struct { float kp; float ki; float kd; float integral; float i_limit; /* 积分限幅防止积分饱和导致超调 */ float last_err; } pid_t; float pid_run(pid_t *pid, float ref, float fdb) { float err ref - fdb; /* 积分项 */ pid-integral pid-ki * err; if (pid-integral pid-i_limit) pid-integral pid-i_limit; if (pid-integral -pid-i_limit) pid-integral -pid-i_limit; /* 微分项默认 kd0 */ float d_err err - pid-last_err; float out pid-kp * err pid-integral pid-kd * d_err; pid-last_err err; return out; }这个 PID 实现有几个工程细节。积分限幅是必备的电机堵转时误差一直在积分会无限累加一旦堵转解除积分项释放会产生很大的过冲限幅把积分项限制在 PI 输出的 20% 左右。另一个细节是 PI 输出本身也建议做限幅比如 q 轴电流环输出限幅到额定电压的 80%给 SVPWM 留出线性调制空间。3.3 SVPWM 扇区判断与占空比计算SVPWM 是整个算法的落地点它把电压矢量从 α、β 轴系变成六路 PWM 的占空比。这套代码用经典的扇区判断加 X、Y、Z 查表法计算量小适合在中断里跑。#define SQRT3 1.73205f typedef struct { uint16_t sector; /* 物理扇区 1~6 */ float t1, t2; /* 相邻基本矢量作用时间 */ float cnt_a, cnt_b, cnt_c; /* 三相比较值相对量 0~1 */ } svpwm_out_t; svpwm_out_t svpwm_calc(float u_alpha, float u_beta, float udc, float ts) { svpwm_out_t out; uint16_t sec 0; float x, y, z, ta, tb, tc; /* 扇区判断三条边界线把矢量平面切成六个 60° 扇区 */ if (u_beta 0.0f) sec | 1; if (SQRT3 * u_alpha - u_beta 0.0f) sec | 2; if (-SQRT3 * u_alpha - u_beta 0.0f) sec | 4; /* sec 值 3/1/5/4/6/2 对应物理扇区 1~6建表映射 */ static const uint16_t map[7] {0, 2, 6, 1, 4, 3, 5}; out.sector map[sec]; /* X、Y、Z 中间变量单位是秒 */ x SQRT3 * u_beta * ts / udc; y (1.5f * u_alpha 0.866f * u_beta) * ts / udc; /* 0.866 sqrt3/2 */ z (-1.5f * u_alpha 0.866f * u_beta) * ts / udc; /* 按扇区分配两个相邻矢量的作用时间 */ switch (out.sector) { case 1: out.t1 -z; out.t2 x; break; case 2: out.t1 y; out.t2 z; break; case 3: out.t1 x; out.t2 -y; break; case 4: out.t1 z; out.t2 -x; break; case 5: out.t1 -y; out.t2 -z; break; case 6: out.t1 -x; out.t2 y; break; } /* 过调制保护作用时间超出周期时按比例压缩 */ float sum out.t1 out.t2; if (sum ts) { out.t1 out.t1 / sum * ts; out.t2 out.t2 / sum * ts; } /* 七段式发波切换时刻T0 均分在波形两端和中间 */ float t0 ts - out.t1 - out.t2; ta t0 * 0.25f; tb ta out.t1 * 0.5f; tc tb out.t2 * 0.5f; out.cnt_a ta / ts; out.cnt_b tb / ts; out.cnt_c tc / ts; return out; }这段代码的输入是上一级逆 Park 变换输出的 u_alpha、u_beta母线电压 udc 和 PWM 周期 ts。u_alpha、u_beta 的单位是伏特udc 也是伏特中间变量算出来的是作用时间秒数。输出 cnt_a、cnt_b、cnt_c 是归一化到 0~1 的比较值外面乘上时基周期 TBPRD 就是写入 ePWM 比较寄存器的值。再把三相比较值按扇区映射到具体的 ePWM 模块这个映射决定触发矢量的开关顺序/* 扇区 1~6 对应的 a、b、c 相切换时刻分配 */ static const uint8_t phase_map[6][3] { {0, 1, 2}, /* 扇区1: cnt_a ta, cnt_b tb, cnt_c tc */ {1, 0, 2}, /* 扇区2 */ {2, 0, 1}, /* 扇区3 */ {2, 1, 0}, /* 扇区4 */ {1, 2, 0}, /* 扇区5 */ {0, 2, 1} /* 扇区6 */ };3.4 电角度获取与转子初始定位电角度的准确性直接决定 FOC 能不能稳定出力。这套工程用增量编码器上电时不知道转子在哪个位置必须先做预定位。常见做法是向 d 轴注入固定电流让转子被磁场拉到与 d 轴对齐的位置这时把编码器计数值清零这个位置就是电角度零点。void foc_align(void) { /* 开环: d 轴注入正向电流q 轴电流为 0 */ pid_id.ref 0.3f * MOTOR_RATED_CURRENT; pid_iq.ref 0.0f; park_out_t align; align.id pid_id.ref; align.iq 0.0f; /* 电角度按 0 处理, 直接把电压矢量打在 d 轴上 */ svpwm_out_t sv svpwm_calc(align.id, -align.iq, UDC, PWM_PERIOD); update_pwm_compare(sv); DELAY_US(500000); /* 等待转子稳定, 500ms 足够 */ /* 清零编码器计数, 以此位置为电角度零点 */ EQep1Regs.QPOSCNT 0; g_align_done 1; }注意这里的 svpwm_calc 输入 u_alpha、u_beta 时如果电角度取 0 且 id 0等价的 u_alpha id 而不是 0这是为了让电压矢量方向与 d 轴重合。实际工程里有人直接让 u_alpha 0、u_beta 0那电机永远不动。预定位之后正常运行时编码器计数乘上 2π 除以每圈脉冲数得到机械角度再乘极对数得到电角度。4. 外设配置与中断架构把算法落到 DSP 上4.1 ePWM 配置中心对齐模式与死区三相全桥下桥臂和上桥臂不能同时导通必须插死区。ePWM 模块自带死区生成功能配置如下void pwm_init(void) { /* 时基: 150MHz 时钟, 中心对齐, 10kHz PWM */ EPwm1Regs.TBPRD 7500; /* 150MHz / (2 * 7500) 10kHz */ EPwm1Regs.TBCTL.bit.CTRMODE 2; /* 增减计数模式 */ EPwm1Regs.TBCTL.bit.HSPCLKDIV 0; /* 高频分频 1 分频 */ EPwm1Regs.TBCTL.bit.CLKDIV 0; /* 时基分频 1 分频 */ /* 动作限定: 下溢输出高, 向上匹配 CMPA 输出低 */ EPwm1Regs.AQCTLA.bit.ZRO 2; /* 下溢时置高 */ EPwm1Regs.AQCTLA.bit.CAU 1; /* 递增匹配时清低 */ EPwm1Regs.AQCTLA.bit.CAD 2; /* 递减匹配时置高 */ /* 死区: 0.5us, 150MHz 下 75 个时钟 */ EPwm1Regs.DBCTL.bit.OUT_MODE 2; /* A/B 都经过死区模块 */ EPwm1Regs.DBCTL.bit.POLSEL 0; /* A 不反相, B 反相 */ EPwm1Regs.DBRED 75; EPwm1Regs.DBFED 75; /* 周期中断: 下溢时触发 CPU 中断 */ EPwm1Regs.ETSEL.bit.INTEN 1; EPwm1Regs.ETSEL.bit.INTSEL 1; /* 计数器0 时中断 */ EPwm1Regs.ETCLR.bit.INT 1; /* 硬件触发 ADC: 计数器0 时发 SOCA 信号 */ EPwm1Regs.ETSEL.bit.SOCAEN 1; EPwm1Regs.ETSEL.bit.SOCASEL 1; }中心对齐模式对应 SVPWM 的七段式发波。TBPRD7500 是用 150MHz 时基时钟除以 2 倍 PWM 频率算出来的增减计数一个完整周期要计数 15000 拍正好对应 10kHz。死区 75 个时钟在 150MHz 下是 0.5 微秒对小功率 IPM 模块够用功率稍大的建议放到 1 微秒以上。4.2 ADC 触发采样避开开关噪声电流采样的时序是 FOC 调试里最容易踩坑的地方。采样点必须避开开关管开关瞬间否则采样到的是充满振铃的开关噪声。这套代码用 ePWM 的 SOC 信号硬件触发 ADC采样点自动落在 PWM 周期的下溢位置也就是载波周期的中点远离开关沿。void adc_init(void) { AdcRegs.ADCTRL1.bit.ACQ_PS 0; /* 采样窗 0 */ AdcRegs.ADCTRL1.bit.SEQ_CAS 0; /* 双排序器 */ AdcRegs.ADCTRL3.bit.SMODE_SEL 1; /* 同步采样模式 */ /* 3 路转换: U/W 相电流 母线电压 */ AdcRegs.ADCMAXCONV.all 2; AdcRegs.ADCCHSELSEQ1.bit.CONV00 0; /* ADCINA0: U 相电流 */ AdcRegs.ADCCHSELSEQ1.bit.CONV01 1; /* ADCINA1: W 相电流 */ AdcRegs.ADCCHSELSEQ1.bit.CONV02 2; /* ADCINA2: 母线电压 */ }ADC 的偏移校准放在初始化阶段做。运放电路的零电流偏置电压不一定在 ADC 量程正中需要在上电后、母线电容放电完成时采一批数据算平均值存起来后续每次电流采样先减这个偏移量再进 Clarke 变换。4.3 EQEP 编码器接口与角度解算void encoder_init(void) { /* 位置计数模式, 使能索引门控 */ EQep1Regs.QDECCTL.bit.QSP 0; EQep1Regs.QDECCTL.bit.IGATE 1; /* 四倍频计数上限: 2500 线 * 4 - 1 */ EQep1Regs.QPOSMAX ENCODER_LINES * 4 - 1; EQep1Regs.QEPCTL.bit.QPEN 1; } float encoder_get_theta(void) { uint32_t pos EQep1Regs.QPOSCNT; float angle_mech (float)pos / (float)(ENCODER_LINES * 4) * 2.0f * PI; /* 电角度 机械角度 * 极对数, 取余保证角度在 0~2π */ float theta angle_mech * MOTOR_POLE_PAIRS; while (theta 2.0f * PI) theta - 2.0f * PI; return theta; }QPOSMAX 必须设成编码器线数乘 4 再减 1EQEP 的硬件四倍频器会对 A、B 两路的每个沿计数2500 线编码器一圈有 10000 个计数。如果 QPOSMAX 设置错误计数溢出后角度会跳变FOC 在高速时表现为突然失步。4.4 控制环路调度三层环路分工整套控制系统是典型的级联结构。最内层是电流环在 ePWM 周期中断里 10kHz 运行中等层是速度环用低速定时器 1kHz 运行最外层位置环在 main 循环里跑频率可以更慢。中断服务程序是整套 FOC 的核心执行现场__interrupt void pwm1_isr(void) { /* 1. 读 ADC 结果, 还原真实电流值 */ float ia adc_read_current(0); float ib adc_read_current(1); /* 2. 取转子电角度 */ float theta encoder_get_theta(); /* 3. Clarke Park 变换 */ clark_out_t clk clark_transform(ia, ib); park_out_t prk park_transform(clk.i_alpha, clk.i_beta, theta); /* 4. 电流环 PI: d 轴电流给 id_ref, q 轴电流给 iq_ref */ float ud pid_run(pid_id, id_ref, prk.id); float uq pid_run(pid_iq, iq_ref, prk.iq); /* 5. 逆 Park 变换到静止坐标系 */ float u_alpha ud * cosf(theta) - uq * sinf(theta); float u_beta ud * sinf(theta) uq * cosf(theta); /* 6. SVPWM 调制成占空比, 写比较寄存器 */ svpwm_out_t sv svpwm_calc(u_alpha, u_beta, UDC, PWM_PERIOD); update_pwm_compare(sv); /* 7. 清中断标志, 响应下一次中断 */ EPwm1Regs.ETCLR.bit.INT 1; PieCtrlRegs.PIEACK.all PIEACK_GROUP3; }id_ref 在普通 FOC 里设为 0也就是让定子电流的励磁分量为零所有电流都用来产生转矩。如果要跑弱磁控制id_ref 改负值就行代码结构不用变。5. 调试避坑FOC 项目的常见问题与排查记录5.1 电流波形毛刺严重电机运行时声音刺耳现象用调试器查看 ADC 采到的相电流波形上面叠加了大量尖刺脉冲电机低速时噪音明显。原因ADC 采样点落在了 PWM 开关沿附近。PWM 周期里开关管开关瞬间母线电压会有很大的 dv/dt通过寄生电容耦合到采样电阻和运放输入端。代码里虽然用了 ePWM 触发 ADC但触发点配置在计数上溢和死区时段重叠了。解决把 SOC 触发点改到计数器下溢位置也就是载波周期的最低点这个位置远离所有开关动作。同时将采样窗 ACQ_PS 从 0 改到 1~2延长采样窗时间让采样电容有充足时间充电到输入电压。改完再看波形毛刺幅度能降一个数量级。5.2 电机猛烈抖动但不转电流环输出饱和现象预定位时转子能吸到固定位置但一接上速度环指令就剧烈抖动母线电流冲到限幅值。原因这是相序错误。U、V、W 三相如果接反电流环输出的电压矢量方向和转子实际位置不匹配导致正反馈。排查时发现 IPM 输出到电机的三相线有一相接反了Clarke 变换算出来的电流方向和实际电机磁场方向差 120 度。解决交换任意两相电机线重新上电测试。做这个排查的时候最稳妥的方式是开环测试给定一个固定电压矢量观察转子转动的方向是否符合预期确认相序后再合闭环。5.3 高速时转矩明显下降电流波形出现削顶现象转速到 3000rpm 附近时q 轴电流要做很大才能维持速度母线电流波形出现平台削顶。原因SVPWM 进入过调制区了。电压矢量的幅值超过了正六边形的内切圆svpwm_calc 里过调制保护触发把 t1、t2 按比例压缩。这时输出电压波形已经畸变谐波分量增加电机的转矩输出能力大幅下降。解决一方面在速度环输出到 iq_ref 之间加限幅避免电流环一直往饱和里打另一方面把 UDC 的取值从实测母线电压改成母线电压的一半给 SVPWM 留出线性调制余量。如果高速性能是刚需就要上弱磁控制用负的 id_ref 去削弱转子磁场这是后话。5.4 电机转到某个位置就掉转矩有明显的顿挫感现象电机匀速转动时在某个机械角度附近转矩明显减少甚至停顿一下才能继续转用调试器看电角度在故障点跳变。原因编码器 Z 信号的标定没做。增量编码器每次上电后计数器不是从 0 开始机械角度始终带着未知偏置。如果只做预定位、不清零 Z 信号随着转速升高累计的位置误差会让电角度在某个点发生跳变。解决有一种做法是在预定位完成后缓慢开环转一圈捕获 Z 信号位置并记录计数值把这个计数值作为零点偏移。从那以后每次上电先找 Z 信号找不到就不允许合闭环。Z 信号位置标定写进编码器初始化流程后这个故障出现的概率几乎降为零。5.5 参数整定越调越震荡电流环频繁过流报警现象按照公式算出来的 PI 参数跑起来电流环振荡试着调小 P 和 I 还是振最后报过流故障。原因PI 参数整定忽略了积分限幅和输出限幅的配合。我之前只改了 kp 和 kii_limit 赖在初始值没动结果积分项在限幅附近来回摆动等效为一个持续激励的振荡源。解决整定电流环时先把积分限幅设为额定电压的 10%pi 限幅设为 50%用带宽法算出初值后单独验证 d 轴电流阶跃响应的超调量只调 kp确认稳态误差能从图表上看出趋势后再逐步放开 ki。从那以后我每次换电机调电流环都强制走一遍完整的限幅检查、阶跃测试、积分项释放验证的流程省下的都是通电烧管的钱。6. 二次开发如何把这份工程改造成自己的电机驱动6.1 换电机时的参数适配流程这套代码的电机参数全部集中在 motor_cfg.h 头文件里换电机只需要动这里参数获取方式影响极对数看铭牌或用测功机测反电动势频率电角度与机械角度的换算比例编码器线数编码器手册QPOSMAX 和角度分辨率相电阻 Rs万用表测线电阻除以 2电流环 ki 初值电机发热估算相电感 Ls电桥测量电流环 kp 初值电流纹波大小额定电流铭牌电流环限幅、预定位电流电流环 PI 初值可以按带宽法估算。设电流环带宽预设为 200Hzkp 约等于 Ls × 2π × 200ki 约等于 Rs × 2π × 200。这个初值不算精确但能让闭环稳定之后用阶跃响应微调。实际调试中我发现 kp 微调的意义比 ki 大得多。6.2 从有感 FOC 改成无感 FOC去掉编码器后转子位置要靠定子电压和电流估算。常见做法是滑模观测器通过检测反电动势间接获得转子位置28335 的浮点运算能力跑一个滑模观测器没什么压力。改造时把 encoder_get_theta() 替换为观测器输出的估计角度启动阶段用 I/F 强拉方式把转子带起来达到 500rpm 左右再切换到观测器闭环。零速和极低速下无感方案没有输出能力这个物理限制想突破就得换高频注入法工作量会明显增加。6.3 增加速度环和位置环在 iq_ref 上面再加一级速度 PI 环就能从电流控制升级成速度控制。速度环输出就是 iq_ref反馈是编码器计算出的转速。速度环带宽远低于电流环一般取电流环的 1/10即 1kHz 左右放在低速定时器中断里执行。位置环再往下就简单了位置误差进位置控制器输出作为速度参考。这套代码的模块划分让加环这件事很自然pid.c 本身就是可复用的速度环和位置环各建一个 pid_t 实例中断里先跑位置环再跑速度环最后跑电流环。改完架构后我把转速阶跃响应和电流波形都拉出来对比过逻辑清晰数据可靠整套东西吃透了之后往无感、弱磁、参数辨识哪个方向掘都有底子。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →