流程解析:從電流環(huán)中斷到無感啟動(dòng)切換)
很多第一次把FOC代碼燒進(jìn)板子的人都會(huì)有一個(gè)困惑這程序到底是怎么轉(zhuǎn)起來的編譯下載之后打開變量觀察窗口看到的是一堆密密麻麻跳動(dòng)的數(shù)字完全不知道哪一行代碼在什么時(shí)刻被執(zhí)行。其實(shí)FOC框架的程序環(huán)流程就是整個(gè)控制器的血液循環(huán)系統(tǒng)搞清楚它讀代碼和調(diào)Bug的效率完全不一樣。這篇繼續(xù)凌歐通用FOC框架的系列解析前面幾篇聊了整體框架、電流采樣與硬件設(shè)計(jì)這一篇專門講程序環(huán)流程中斷里怎么跑電流環(huán)、主循環(huán)里怎么調(diào)度慢環(huán)、無感啟動(dòng)怎么切閉環(huán)、狀態(tài)機(jī)怎么防止系統(tǒng)飛了。凌歐通用FOC框架的程序環(huán)設(shè)計(jì)思路和市面上主流FOC框架ST SDK、SimpleFOC、VESC有相似之處但它在流程劃分、狀態(tài)切換和保護(hù)機(jī)制上有自己的一套取舍尤其適合做無感FOC和電流速度FOC控制的人學(xué)習(xí)。無論你是剛?cè)腴T的無感FOC學(xué)習(xí)者還是在做PMSM無感FOC控制的工程師或者正被FOC調(diào)試難點(diǎn)折磨的老手這篇文章都值得從頭讀到尾。下文所有流程都是基于實(shí)際代碼精簡(jiǎn)后的結(jié)構(gòu)不同版本的寄存器名可能有差異但邏輯骨架是一致的。1. 程序環(huán)為什么必須快慢分層凌歐框架的調(diào)度骨架1.1 三個(gè)閉環(huán)的物理時(shí)間常數(shù)決定了執(zhí)行頻率FOC控制的本質(zhì)是三個(gè)閉環(huán)電流環(huán)、速度環(huán)、位置環(huán)。三個(gè)環(huán)的執(zhí)行頻率必須由快到慢逐級(jí)遞減這不是代碼風(fēng)格偏好而是受控對(duì)象的物理規(guī)律決定的。先看電氣量電機(jī)定子繞組是電阻和電感的串聯(lián)電氣時(shí)間常數(shù)通常只有幾毫秒甚至亞毫秒。電流必須被高頻調(diào)節(jié)否則電流波動(dòng)劇烈、轉(zhuǎn)矩脈動(dòng)大、電機(jī)發(fā)熱嚴(yán)重。再看機(jī)械量轉(zhuǎn)子本身有轉(zhuǎn)動(dòng)慣量速度變化是慢過程機(jī)械時(shí)間常數(shù)往往是電氣時(shí)間常數(shù)的幾十倍。因此速度環(huán)沒必要和電流環(huán)一樣快位置換就更慢了。如果嘗試把三個(gè)環(huán)都塞進(jìn)同一個(gè)while(1)大循環(huán)里順序執(zhí)行程序會(huì)非常尷尬循環(huán)里一旦有通信處理、按鍵掃描這種耗時(shí)操作電流環(huán)的執(zhí)行周期就會(huì)抖動(dòng)電流波形隨之產(chǎn)生毛刺。你可能覺得周期抖動(dòng)幾十微秒無所謂但電流環(huán)對(duì)執(zhí)行時(shí)間的一致性極度敏感周期抖動(dòng)直接表現(xiàn)為占空比抖動(dòng)最終在相電流波形上看到毛刺電機(jī)噪音變大、開關(guān)管應(yīng)力變差。所以所有實(shí)際可用的FOC框架無一例外都采用快慢環(huán)分治。1.2 主循環(huán)與中斷循環(huán)的職責(zé)邊界凌歐框架的調(diào)度骨架分三層最快層PWM中斷或ADC中斷頻率等于開關(guān)頻率典型值8kHz到20kHz。這一層只跑電流環(huán)、保護(hù)邏輯和觀測(cè)器更新無感模式。中間層主循環(huán)里的速度環(huán)和位置環(huán)通過節(jié)拍計(jì)數(shù)器分時(shí)調(diào)度典型值1kHz和500Hz。慢速層主循環(huán)里的通信處理、狀態(tài)機(jī)、參數(shù)修改、故障恢復(fù)按需執(zhí)行不占固定節(jié)拍。中斷里跑電流環(huán)主循環(huán)里跑慢環(huán)這個(gè)分工有兩個(gè)直接好處。第一電流環(huán)的執(zhí)行頻率與主循環(huán)里做什么完全解耦無論通信處理多繁忙電流環(huán)的周期始終嚴(yán)格等于PWM周期。第二慢環(huán)可以容忍執(zhí)行時(shí)間的微小抖動(dòng)比如串口一幀數(shù)據(jù)解析耗時(shí)掉0.5ms這對(duì)1kHz的速度環(huán)影響可以忽略。從代碼結(jié)構(gòu)上看主循環(huán)不應(yīng)該出現(xiàn)任何阻塞延時(shí)。一旦delay_ms(5)出現(xiàn)在主循環(huán)里通信處理延遲、故障掃描延遲、速度環(huán)節(jié)拍全部跟隨抖動(dòng)FOC就再也不絲滑了。凌歐框架在主循環(huán)里用一個(gè)節(jié)拍計(jì)數(shù)器來分發(fā)任務(wù)本質(zhì)上是把時(shí)間片調(diào)度功能下沉到主循環(huán)內(nèi)部后面第3章會(huì)展開講。1.3 跨環(huán)數(shù)據(jù)交換的防撕裂處理這是程序環(huán)設(shè)計(jì)中最容易被忽略的一環(huán)但實(shí)際工程里踩坑概率極高。主循環(huán)和中斷之間要交換很多變量速度環(huán)算出的iq_ref要讓電流環(huán)用位置環(huán)算出的speed_ref要讓速度環(huán)用上位機(jī)改寫的PI參數(shù)要讓電流環(huán)讀取。問題在于中斷隨時(shí)可能打斷主循環(huán)的賦值操作。舉個(gè)例子主循環(huán)里正在寫一個(gè)4字節(jié)的浮點(diǎn)變量iq_ref寫到一半突然來了PWM中斷此時(shí)中斷里的電流環(huán)讀取iq_ref就會(huì)得到一半新值一半舊值。如果新舊值差異很大比如速度環(huán)更新了一版iq_ref而電流環(huán)正好讀到撕裂值等效電流瞬間跳變輕則噪聲重則過流。凌歐框架的做法是對(duì)環(huán)間共享變量做原子訪問保護(hù)具體有兩種手段一是關(guān)中斷賦值在寫入的關(guān)鍵時(shí)刻屏蔽PWM中斷寫完后恢復(fù)二是使用雙緩沖副本主循環(huán)寫副本電流環(huán)讀主副本依靠一個(gè)更新標(biāo)志來切換。我強(qiáng)烈建議每個(gè)自研FOC框架都用同樣的手段這個(gè)坑我實(shí)際踩過一次表現(xiàn)是電機(jī)高速轉(zhuǎn)的時(shí)候偶爾咔一聲查了小半個(gè)月才定位到是iq_ref撕裂讀取。2. 電流環(huán)在中斷里的完整執(zhí)行流程從ADC采樣到SVPWM更新2.1 從ADC采樣到PWM更新的十個(gè)步驟FOC的電流環(huán)是結(jié)果最明確的一段流程從采樣到占空比更新基本是一個(gè)單向流水線。凌歐框架在ADC中斷與PWM同步觸發(fā)里依次執(zhí)行十個(gè)步驟讀取ADC電流采樣值兩相電流第三相由基爾霍夫定律推算。電流零位偏移修正。獲取轉(zhuǎn)子角度編碼器、磁編碼器或觀測(cè)器估算值。Clark變換把三相靜止坐標(biāo)系轉(zhuǎn)到兩相靜止坐標(biāo)系。Park變換把兩相靜止坐標(biāo)系轉(zhuǎn)到兩相旋轉(zhuǎn)坐標(biāo)系。電流誤差計(jì)算與PI調(diào)節(jié)得到d軸和q軸電壓指令。電壓前饋補(bǔ)償反電動(dòng)勢(shì)解耦。反Park變換把d/q軸電壓指令轉(zhuǎn)到兩相靜止坐標(biāo)系。SVPWM調(diào)制計(jì)算三相占空比。更新PWM比較寄存器。這段流程的偽代碼如下不同版本的寄存器名有差異但結(jié)構(gòu)一致void PWM_ISR(void) { DEBUG_PIN_HIGH(); // 調(diào)試點(diǎn)用來量中斷執(zhí)行時(shí)間 // 1. 讀取兩相電流第三相推算 ia adc_buf[0]; ib adc_buf[1]; ic -ia - ib; // 2. 零位偏移修正 ia - ia_zero_offset; ib - ib_zero_offset; // 3. 轉(zhuǎn)子角度采集 theta get_rotor_angle(); // 4. Clark變換 i_alpha ia; i_beta (ia 2.0f * ib) * 0.577350269f; // 5. Park變換 sin_t arm_sin_f32(theta); cos_t arm_cos_f32(theta); id i_alpha * cos_t i_beta * sin_t; iq -i_alpha * sin_t i_beta * cos_t; // 6. 電流環(huán)PI vd pi_update(pi_d, id_ref, id); vq pi_update(pi_q, iq_ref, iq); // 7. 反電動(dòng)勢(shì)解耦前饋 vd vd_feedforward; vq vq_feedforward; // 8. 反Park變換 v_alpha vd * cos_t - vq * sin_t; v_beta vd * sin_t vq * cos_t; // 9. SVPWM占空比計(jì)算 svpwm_calc(v_alpha, v_beta, duty_a, duty_b, duty_c); // 10. 更新比較寄存器 pwm_set_duty(duty_a, duty_b, duty_c); // 保護(hù)邏輯與觀測(cè)器更新 protection_check(); if (sensorless_mode) observer_update(ia, ib, v_alpha, v_beta); DEBUG_PIN_LOW(); }2.2 采樣觸發(fā)時(shí)刻與零漂處理采樣時(shí)刻為什么這么關(guān)鍵PWM中心對(duì)齊模式下載波頂點(diǎn)時(shí)刻電感電流的紋波正好回到平均值同時(shí)開關(guān)管切換造成的共模干擾也在這一瞬間最小。ADC觸發(fā)必須和PWM同步設(shè)置在頂點(diǎn)不要在計(jì)數(shù)零點(diǎn)或比較值突變處采樣否則采出來的電流疊加了大量開關(guān)噪聲反饋到電流環(huán)里就是占空比抖動(dòng)占空比抖動(dòng)又造成電流紋波變大形成惡性循環(huán)。凌歐框架在PWM配置里用一個(gè)定時(shí)器同步事件去觸發(fā)ADC所有通道采集完再進(jìn)中斷從根本上保證采樣同步。如果你在自研框架里遇到電流波形異常第一步永遠(yuǎn)是拿示波器看PWM同步信號(hào)和ADC觸發(fā)信號(hào)是否嚴(yán)格對(duì)齊這個(gè)排查成本最低但收益最大。零漂問題同樣容易被忽視。電流傳感器霍爾、采樣電阻運(yùn)放在零電流時(shí)輸出電壓不可能是絕對(duì)的ADC中值運(yùn)放失調(diào)、溫度漂移都會(huì)造成零點(diǎn)偏移。如果不在程序環(huán)里做零漂校正反饋電流就帶著直流分量直軸和交軸電流軌跡在示波器上呈現(xiàn)偏心圓實(shí)際表現(xiàn)是電機(jī)空載電流偏大、低速抖動(dòng)。凌歐框架在電機(jī)停止時(shí)采集幾十次電流取平均作為零漂值存下來每次進(jìn)入中斷時(shí)減去這個(gè)偏移量。這個(gè)校正必須在電機(jī)上電后靜止?fàn)顟B(tài)下執(zhí)行電機(jī)一旦轉(zhuǎn)起來得到的平均值就混合了真實(shí)電流校出來的偏移量是錯(cuò)的。2.3 電流PI的積分抗飽和與前饋補(bǔ)償電流環(huán)PI調(diào)節(jié)器在程序環(huán)里的實(shí)現(xiàn)有三個(gè)必須處理的細(xì)節(jié)。第一積分分離。當(dāng)速度環(huán)修改了iq_ref電流誤差瞬間變得很大如果積分項(xiàng)還按常態(tài)累加容易超調(diào)。凌歐框架的PI結(jié)構(gòu)里帶積分快速清零邏輯每次速度環(huán)更新目標(biāo)值到電流環(huán)執(zhí)行之間電流PI的積分項(xiàng)會(huì)按設(shè)定軌跡衰減或者直接清零避免目標(biāo)值階躍時(shí)積分項(xiàng)沖過頭。第二輸出限幅和積分抗飽和。當(dāng)PI輸出到達(dá)電壓限幅時(shí)積分項(xiàng)必須停止累加否則會(huì)產(chǎn)生積分飽和表現(xiàn)為恢復(fù)瞬間大超調(diào)。說得直白一點(diǎn)你想讓電流快速上升但PWM已經(jīng)頂?shù)阶畲笳伎毡攘薖I的輸出還在往上積等到電流終于追上目標(biāo)時(shí)積分項(xiàng)仍然很大輸出還是滿的電流繼續(xù)超調(diào)等積分項(xiàng)慢慢退下來已經(jīng)過了好多個(gè)周期。所以程序環(huán)里必須在每次PI運(yùn)算前判斷輸出是否達(dá)到限幅達(dá)到就凍結(jié)積分累加。第三前饋補(bǔ)償。如果只做PI控制而不做反電動(dòng)勢(shì)解耦高速時(shí)d軸和q軸會(huì)互相干擾你加大iqid會(huì)被拉偏動(dòng)態(tài)響應(yīng)明顯變差。反電動(dòng)勢(shì)解耦的前饋項(xiàng)基本形式是vd_ff -omega * Lq * iq vq_ff omega * (Ld * id flux_f)其中omega是電角速度Ld和Lq是d/q軸電感flux_f是永磁磁鏈。前饋值不必在電流環(huán)里每周期重算可以在速度環(huán)里算好放到共享變量里電流環(huán)只負(fù)責(zé)讀取。注意這個(gè)讀取同樣存在撕裂風(fēng)險(xiǎn)要用和共享變量一致的原子訪問方式。3. 主循環(huán)中速度環(huán)與位置環(huán)的分時(shí)調(diào)度3.1 節(jié)拍計(jì)數(shù)器的分時(shí)調(diào)度邏輯速度環(huán)和位置環(huán)在主循環(huán)里怎么插空?qǐng)?zhí)行凌歐框架在主循環(huán)里維護(hù)了一個(gè)節(jié)拍標(biāo)志每次循環(huán)判斷是否到了對(duì)應(yīng)任務(wù)的執(zhí)行節(jié)拍。速度環(huán)典型值1kHz也就是每1ms跑一次位置環(huán)按需可以500Hz甚至更低通信模塊每次循環(huán)都處理但不占用固定節(jié)拍。主循環(huán)的偽代碼如下while (1) { if (tick_1ms_flag) { speed_pi_run(); tick_1ms_flag 0; } if (tick_2ms_flag) { position_ctrl_run(); tick_2ms_flag 0; } fsm_run(); comm_process(); fault_monitor(); }tick標(biāo)志由定時(shí)器中斷置位主循環(huán)只負(fù)責(zé)輪詢這樣設(shè)計(jì)的好處是即使主循環(huán)某一輪卡得比較久慢環(huán)任務(wù)也只會(huì)在下一個(gè)循環(huán)繼續(xù)執(zhí)行不會(huì)出現(xiàn)重入問題。這里我想特別強(qiáng)調(diào)一點(diǎn)不要用阻塞延時(shí)來做慢環(huán)節(jié)拍。很多從單片機(jī)裸機(jī)開發(fā)轉(zhuǎn)過來的人喜歡在主循環(huán)里delay一次延時(shí)5ms看起來沒毛病但通信處理和故障掃描全被延后了。假如串口正在接收上位機(jī)下發(fā)的參數(shù)一幀數(shù)據(jù)分多次接收接收過程中主循環(huán)卡了5ms串口緩沖區(qū)溢出參數(shù)寫不進(jìn)。所以FOC框架里的主循環(huán)必須是無阻塞輪詢結(jié)構(gòu)。3.2 速度環(huán)輸出iq_ref的兩層限幅速度環(huán)的本質(zhì)是速度PI調(diào)節(jié)器輸出的是q軸電流指令iq_ref。核心語句可以簡(jiǎn)化為speed_pi_out kp_speed * (speed_ref - speed_fb) ki_speed * integral_speed; iq_ref limit_and_slew_rate(speed_pi_out, current_limit);這里我特意寫了一個(gè)limit_and_slew_rate限幅加斜坡限制因?yàn)閕q_ref的限幅必須做兩層。第一層是速度PI輸出限幅限幅值一般就是系統(tǒng)允許的最大電流。這一層很好理解速度誤差再大電流也不能超過逆變器和電機(jī)的耐受值。第二層是變化率限制也就是斜坡限制限制iq_ref在單位時(shí)間內(nèi)能變化多少。為什么要做這一層假設(shè)上位機(jī)突然給了個(gè)大的轉(zhuǎn)速階躍速度環(huán)輸出瞬間就頂?shù)较薹等绻鹖q_ref直接跳變到最大電流沖擊電流和機(jī)械沖擊都會(huì)很大。加斜坡限制后iq_ref是逐漸爬升到限幅值的電流變化柔和也更符合機(jī)械系統(tǒng)對(duì)力矩變化率的容忍度。LingOu框架里這個(gè)斜坡限制的速度是可以配置的單位是安培每秒。我調(diào)試時(shí)一般取額定電流的10倍每秒作為默認(rèn)值比如額定電流10A斜坡限制就是100A/s從0到額定電流需要0.1秒。這個(gè)值不是越大越好也不是越小越好需要根據(jù)負(fù)載的轉(zhuǎn)動(dòng)慣量和應(yīng)用場(chǎng)景折衷。速度反饋的來源也要注意。有傳感器時(shí)用編碼器差分計(jì)算代碼上分M法測(cè)頻率和T法測(cè)周期兩種無感時(shí)用觀測(cè)器估算速度。無論哪種速度環(huán)的執(zhí)行頻率不能超過傳感器速度更新的實(shí)際分辨率否則會(huì)引入大量量化噪聲。比如編碼器線數(shù)很低速度環(huán)頻率卻很高就會(huì)出現(xiàn)速度反饋跳變、噪聲放大的現(xiàn)象。3.3 位置環(huán)與指令軌跡規(guī)劃位置環(huán)在凌歐框架里不是直接對(duì)位置誤差做比例控制這么簡(jiǎn)單。如果直接做P控制目標(biāo)位置階躍遠(yuǎn)的時(shí)候速度指令會(huì)瞬間頂?shù)綐O限電機(jī)會(huì)猛加速然后猛減速機(jī)械沖擊損毀設(shè)備。實(shí)際框架會(huì)先做軌跡規(guī)劃把目標(biāo)位置翻譯成一條梯形速度曲線或S形速度曲線位置環(huán)輸出速度指令速度環(huán)再跟蹤這條速度曲線。這樣就形成了指令信號(hào)發(fā)生器三級(jí)跟隨器的級(jí)聯(lián)結(jié)構(gòu)位置環(huán)輸入來自上位機(jī)預(yù)設(shè)的目標(biāo)位置輸出是速度指令speed_ref。速度環(huán)輸入是speed_ref輸出是q軸電流指令iq_ref。電流環(huán)輸入是iq_ref輸出是PWM占空比。三級(jí)環(huán)的數(shù)據(jù)流永遠(yuǎn)是單向的位置環(huán)算得快慢不影響速度環(huán)速度環(huán)算得快慢不影響電流環(huán)只要接口變量做了撕裂防護(hù)各層之間就是松耦合的。這也是FOC框架能穩(wěn)定運(yùn)行的基礎(chǔ)。從執(zhí)行頻率上看三個(gè)環(huán)的典型值和反饋來源可以整理成一張表控制層級(jí)典型執(zhí)行頻率反饋來源輸出電流環(huán)8kHz~20kHzADC采樣電流、角度vd、vq速度環(huán)0.5kHz~2kHz編碼器/觀測(cè)器速度iq_ref位置環(huán)100Hz~1kHz編碼器/觀測(cè)器角度speed_ref位置環(huán)下面還能掛梯形曲線發(fā)生器曲線發(fā)生器本身不參與閉環(huán)反饋它只負(fù)責(zé)生成一條平滑的速度參考曲線算出來的speed_ref才送給速度環(huán)。這樣一來位置指令的大跳變被曲線發(fā)生器消化了整個(gè)級(jí)聯(lián)結(jié)構(gòu)承受的沖擊就小很多。4. 無感FOC啟動(dòng)鏈路程序環(huán)里最容易出錯(cuò)的一段4.1 轉(zhuǎn)子初始位置檢測(cè)的三種實(shí)現(xiàn)很多人的問題都集中在無感FOC啟動(dòng)上核心難點(diǎn)第一關(guān)就是轉(zhuǎn)子初始位置檢測(cè)。無感模式?jīng)]有編碼器告訴程序轉(zhuǎn)子當(dāng)前轉(zhuǎn)到了哪個(gè)角度而FOC的Park變換又必須知道精確的轉(zhuǎn)子角度啟動(dòng)前必須先解決我在哪里的問題。凌歐框架里有三種初始位置檢測(cè)方式區(qū)別在負(fù)載能力和代碼復(fù)雜度預(yù)定位法發(fā)一個(gè)固定方向的電壓矢量把轉(zhuǎn)子硬拉到一個(gè)已知角度。實(shí)現(xiàn)最簡(jiǎn)單空載或輕載場(chǎng)景下可靠缺點(diǎn)是轉(zhuǎn)子會(huì)轉(zhuǎn)動(dòng)一下有些應(yīng)用不允許這種位移。脈沖矢量檢測(cè)法輪流在多個(gè)方向發(fā)短脈沖電壓比較電流響應(yīng)幅值判斷磁極方向再用正反脈沖做磁極極性區(qū)分。轉(zhuǎn)子基本不移動(dòng)適合有一定負(fù)載的場(chǎng)合。核心原理是利用d軸和q軸磁路的差異脈沖電壓方向越接近轉(zhuǎn)子d軸電感越小、電流響應(yīng)越大。高頻注入法在估計(jì)d軸注入高頻電壓信號(hào)從高頻電流響應(yīng)中解調(diào)出位置誤差再收斂到真實(shí)角度。零速帶載能力最強(qiáng)但算法復(fù)雜度高對(duì)電機(jī)凸極率有要求不是所有電機(jī)都適合。凌歐框架的默認(rèn)做法是先走預(yù)定位等電流穩(wěn)定后再用脈沖矢量法確認(rèn)一次磁極。這樣做的邏輯是預(yù)定位負(fù)責(zé)把轉(zhuǎn)子拉到一個(gè)大概位置給脈沖法一個(gè)初始參考脈沖法負(fù)責(zé)驗(yàn)證和糾偏防止預(yù)定位因?yàn)樨?fù)載力矩太大而沒拉到位。兩級(jí)配合下來簡(jiǎn)單場(chǎng)景不增加成本復(fù)雜場(chǎng)景也有保底精度。這個(gè)階段在代碼里是放在主循環(huán)狀態(tài)機(jī)的ALIGN狀態(tài)下執(zhí)行的完成標(biāo)志置位后才切到START。我調(diào)試時(shí)的經(jīng)驗(yàn)是定位階段的作用時(shí)間不能太短尤其是大慣量負(fù)載轉(zhuǎn)子被拉過去需要時(shí)間一般至少給100ms以上。時(shí)間太短轉(zhuǎn)子還沒穩(wěn)定位置其實(shí)還是錯(cuò)的。4.2 開環(huán)強(qiáng)拖用手扶著轉(zhuǎn)起來轉(zhuǎn)子初始位置檢測(cè)完成后程序環(huán)進(jìn)入開環(huán)強(qiáng)拖階段。這個(gè)階段的本質(zhì)是用手扶著轉(zhuǎn)起來既然觀測(cè)器在零速和極低速下無法可靠工作反電動(dòng)勢(shì)太弱信噪比太低那就先不給轉(zhuǎn)子精確的控制角度而是直接給一個(gè)旋轉(zhuǎn)的電流矢量強(qiáng)制轉(zhuǎn)子跟著轉(zhuǎn)。相當(dāng)于先把轉(zhuǎn)子帶起來等轉(zhuǎn)速足夠高、反電動(dòng)勢(shì)足夠強(qiáng)的時(shí)候再把控制權(quán)交給觀測(cè)器和閉環(huán)。凌歐框架的實(shí)測(cè)代碼里開環(huán)強(qiáng)拖用I/F方式實(shí)現(xiàn)電流環(huán)仍然正常工作但id_ref設(shè)置為0iq_ref固定為一個(gè)啟動(dòng)電流值角度不是來自觀測(cè)器而是程序自己以固定斜率遞增。也就是說程序假裝知道角度用一個(gè)勻速旋轉(zhuǎn)的虛擬角度去驅(qū)動(dòng)Park變換和反Park變換實(shí)際上轉(zhuǎn)子在電流矢量牽引下跟著轉(zhuǎn)。程序的啟動(dòng)參數(shù)有兩個(gè)是最關(guān)鍵的啟動(dòng)電流和角度加速斜率。啟動(dòng)電流通常取額定電流的1.5倍左右。太小了拖不動(dòng)負(fù)載尤其是有靜摩擦或帶載的場(chǎng)合太大了容易過流或者強(qiáng)拖過程中發(fā)熱嚴(yán)重。角度加速斜率對(duì)應(yīng)轉(zhuǎn)子的加速度斜率越大啟動(dòng)越快但越容易失步。我調(diào)試時(shí)會(huì)讓加速率從很小開始試比如200rpm/s如果電機(jī)起得來且不抖動(dòng)再逐漸加大帶重負(fù)載時(shí)一般減半處理。開環(huán)強(qiáng)拖階段容易出現(xiàn)的坑是電機(jī)發(fā)出了嗡嗡聲但不轉(zhuǎn)。這通常意味著啟動(dòng)電流不夠或者加速斜率太大、轉(zhuǎn)子跟不上虛擬角度的變化。還有一種情況是定位階段根本沒有定位成功轉(zhuǎn)子在錯(cuò)誤的角度上被強(qiáng)拖表現(xiàn)為電流很大但轉(zhuǎn)矩很小。4.3 觀測(cè)器切入與閉環(huán)平滑切換切換閉環(huán)是整個(gè)無感啟動(dòng)成敗的關(guān)鍵。凌歐框架的切換條件有三個(gè)全部滿足才允許切換轉(zhuǎn)速達(dá)到閾值一般取額定轉(zhuǎn)速的5%到10%。太低時(shí)觀測(cè)器速度估計(jì)抖得厲害切換后容易振蕩太高會(huì)浪費(fèi)啟動(dòng)時(shí)間啟動(dòng)過程看起來拖沓。觀測(cè)器角度收斂角度誤差在設(shè)定閾值范圍內(nèi)并且持續(xù)一段時(shí)間。持續(xù)確認(rèn)這一步很重要觀測(cè)器偶爾會(huì)有一兩個(gè)周期的角度跳變瞬時(shí)滿足不代表穩(wěn)定收斂。強(qiáng)拖電流無持續(xù)超調(diào)說明負(fù)載變化不劇烈切換起來不會(huì)猛沖。三個(gè)條件都滿足后程序環(huán)做一系列平滑交接動(dòng)作。第一步將強(qiáng)拖用的虛擬斜坡角度替換為觀測(cè)器輸出角度。替換前必須檢查兩個(gè)角度是否在允許偏差范圍內(nèi)如果偏差太大說明強(qiáng)拖過程中轉(zhuǎn)子已經(jīng)和虛擬角度錯(cuò)位了硬切會(huì)導(dǎo)致電流瞬間跳變。正確做法是延長切換等待等虛擬角度和觀測(cè)器角度跑攏了再切。第二步將強(qiáng)拖用的固定iq_ref替換為速度環(huán)輸出iq_ref。同樣不能瞬時(shí)跳變要用斜坡漸變的方式切換。一般讓強(qiáng)拖電流在幾十毫秒內(nèi)逐漸過渡到速度環(huán)輸出的值這樣電流的變化是連續(xù)的力矩不會(huì)突變。第三步速度環(huán)的積分項(xiàng)要做預(yù)置。直接讓速度環(huán)切入積分項(xiàng)從0開始累加會(huì)導(dǎo)致切入瞬間速度環(huán)輸出很小和強(qiáng)拖電流之間出現(xiàn)一個(gè)臺(tái)階。凌歐框架的做法是把強(qiáng)拖電流值作為速度環(huán)積分的初始值相當(dāng)于速度環(huán)已經(jīng)熱身好了接手的瞬間就能輸出接近強(qiáng)拖電流的值然后再根據(jù)速度誤差逐步調(diào)整。這段邏輯在程序環(huán)里通常表現(xiàn)為一個(gè)小的狀態(tài)子機(jī)代碼結(jié)構(gòu)類似case START: if (smo_angle_ready speed switch_speed) { if (angle_error ANGLE_LIMIT) { state RUN; iq_ref_ramp_start current_iq_forced; } } break; case RUN: // iq_ref從強(qiáng)拖值在設(shè)定時(shí)間內(nèi)漸變到速度環(huán)輸出 iq_ref ramp_to(speed_loop_output, iq_ref_ramp_start, ramp_ms); break;切換瞬間如果電機(jī)咔的一聲或者電流尖峰優(yōu)先檢查兩個(gè)地方切換前提的角度差限值以及iq_ref漸變時(shí)間。這個(gè)經(jīng)驗(yàn)來自我實(shí)際調(diào)無感FOC的過程波形上的異常最常出現(xiàn)在切換前100ms和切換后200ms只要這段時(shí)間電流是平滑的整個(gè)啟動(dòng)就算成功了。步進(jìn)電機(jī)做FOC的啟動(dòng)流程其實(shí)完全一致只不過步進(jìn)電機(jī)是磁阻加永磁混合結(jié)構(gòu)凸極性強(qiáng)、電感小初始位置檢測(cè)用脈沖法或高頻注入可以做得很準(zhǔn)。步進(jìn)電機(jī)一般不需要零速大扭矩預(yù)定位法很多時(shí)候也夠用。如果你想拿凌歐框架帶步進(jìn)電機(jī)做位置控制程序環(huán)不用改改電機(jī)參數(shù)和啟動(dòng)策略就行。5. 主循環(huán)狀態(tài)機(jī)與調(diào)試通信通道防止系統(tǒng)飛了的核心設(shè)計(jì)5.1 生命周期狀態(tài)與狀態(tài)切換規(guī)則一個(gè)FOC系統(tǒng)不是只有運(yùn)行態(tài)。從用戶按下啟動(dòng)鍵到運(yùn)行中遇到故障整個(gè)生命周期都應(yīng)該在狀態(tài)機(jī)里被邏輯化。凌歐框架的主循環(huán)里有一個(gè)精簡(jiǎn)但完整的有限狀態(tài)機(jī)狀態(tài)定義通常包括IDLE待機(jī)狀態(tài)PWM沒有輸出等待啟動(dòng)指令。ALIGN定位和初始位置檢測(cè)階段。START開環(huán)強(qiáng)拖階段。RUN閉環(huán)運(yùn)行階段。FAULT故障保護(hù)階段。STOP軟停機(jī)階段。為什么必須用狀態(tài)機(jī)而不是直接在主循環(huán)里寫大量if else因?yàn)闋顟B(tài)機(jī)會(huì)讓每個(gè)階段的入口和出口變得明確。比如從RUN進(jìn)入FAULT要執(zhí)行封波、記錄故障碼、停止速度環(huán)三件事如果這些操作散落在主循環(huán)的各段代碼里漏掉任何一個(gè)都會(huì)留下隱患。狀態(tài)機(jī)把所有進(jìn)入某個(gè)狀態(tài)時(shí)應(yīng)該做什么收斂到一個(gè)地方可讀性和可靠性都明顯更高。狀態(tài)機(jī)在主循環(huán)里執(zhí)行執(zhí)行頻率不需要很高狀態(tài)切換是慢動(dòng)作事件。但狀態(tài)機(jī)與電流環(huán)之間有個(gè)關(guān)鍵的交互電流環(huán)在中斷里不跑狀態(tài)機(jī)但它會(huì)讀取狀態(tài)機(jī)設(shè)定的運(yùn)行模式標(biāo)志比如是否封波、是否處于強(qiáng)拖階段。這些標(biāo)志必須在中斷里用于保護(hù)判斷如果封波標(biāo)志已經(jīng)置位電流環(huán)這周期就不能再輸出PWM占空比。5.2 故障分級(jí)與自恢復(fù)策略凌歐框架的FAULT狀態(tài)不是單一的狀態(tài)而是帶故障碼和恢復(fù)等級(jí)的。程序環(huán)里常見故障包括過流、過壓、欠壓、堵轉(zhuǎn)、過溫、通信超時(shí)、編碼器斷線。故障分級(jí)的意義在于恢復(fù)策略不同。一級(jí)故障比如瞬時(shí)過流、通信超時(shí)可以自動(dòng)恢復(fù)延時(shí)幾百毫秒后嘗試重新啟動(dòng)。二級(jí)故障比如過壓、堵轉(zhuǎn)、過溫需要人工干預(yù)或者滿足特定條件才能復(fù)位例如溫度降到安全區(qū)間以下。三級(jí)故障比如硬件自檢失敗、編碼器斷線必須整機(jī)上電復(fù)歸不能自己恢復(fù)。把故障分級(jí)放進(jìn)程序環(huán)里實(shí)際效果是瞬時(shí)過流后電機(jī)自動(dòng)重啟用戶不需要停機(jī)而過溫會(huì)一直停在FAULT狀態(tài)直到溫度回落。很多燒板子的案例是三級(jí)故障未處理過壓一直累積最終功率管擊穿。所以故障狀態(tài)的處理不是簡(jiǎn)單的封波停機(jī)而是要有策略的。軟停機(jī)狀態(tài)也值得一提。正常停機(jī)不是直接把PWM封掉否則大慣量負(fù)載會(huì)因?yàn)榱⒓葱兜袅囟蜎_一段。凌歐框架的軟停機(jī)邏輯是先讓速度環(huán)以設(shè)定減速度斜坡降到0然后切換到IDLE最后才封波。這個(gè)流程在狀態(tài)機(jī)里表現(xiàn)為STOP狀態(tài)到IDLE狀態(tài)的轉(zhuǎn)換期間程序環(huán)持續(xù)運(yùn)行控制算法只是目標(biāo)速度在往下走。5.3 非阻塞通信與寄存器映射調(diào)參通信模塊在程序環(huán)里的地位說起來不算控制環(huán)但調(diào)試時(shí)它是命脈。凌歐框架用的是寄存器映射通信方式上位機(jī)通過串口或CAN直接讀寫變量地址。這種設(shè)計(jì)的好處是不需要為每個(gè)參數(shù)寫單獨(dú)的接收協(xié)議分支主循環(huán)里只要有一個(gè)參數(shù)讀寫執(zhí)行器上位機(jī)發(fā)什么地址就讀寫什么寄存器代碼量小且擴(kuò)展性好。程序環(huán)側(cè)需要保證的是通信處理不能阻塞控制鏈。串口接收、校驗(yàn)、組幀、應(yīng)答全部做成非阻塞狀態(tài)機(jī)逐字節(jié)接收收到一幀完整數(shù)據(jù)再統(tǒng)一解析。這樣即使串口在主循環(huán)里慢慢收也不會(huì)卡住速度環(huán)的節(jié)拍。我的調(diào)試習(xí)慣是用上位機(jī)在線改PI參數(shù)這比改代碼重新編譯燒錄快得多。但前提是代碼里要給每個(gè)可調(diào)參數(shù)加范圍保護(hù)上位機(jī)寫進(jìn)寄存器的值如果超出合理范圍框架會(huì)直接拒絕寫入防止在電機(jī)運(yùn)行時(shí)把P參數(shù)改成100倍把系統(tǒng)打飛。這個(gè)范圍保護(hù)看起來是小事但關(guān)鍵時(shí)刻能救一塊驅(qū)動(dòng)板。6. 程序環(huán)調(diào)試的常見坑與完整排查鏈路6.1 電流波形異常與電機(jī)噪音的排查FOC調(diào)試難點(diǎn)集中在波形異常、噪音、啟動(dòng)失敗、中斷超時(shí)這幾個(gè)方向我按程序環(huán)相關(guān)的常見坑整理一下排查思路。電流波形毛刺嚴(yán)重時(shí)先確認(rèn)采樣時(shí)刻用示波器測(cè)PWM中心對(duì)齊信號(hào)和ADC觸發(fā)信號(hào)是否嚴(yán)格同步不同步就會(huì)采到開關(guān)噪聲。再查電流零漂電機(jī)停止時(shí)電流讀數(shù)應(yīng)當(dāng)接近0如果漂移了幾個(gè)LSB反饋電流就含有直流分量波形上表現(xiàn)為id和iq軌跡偏心。最后查速度環(huán)輸出iq_ref是否在電流環(huán)允許范圍內(nèi)是否存在撕裂讀取的問題。電機(jī)低速抖動(dòng)、高速尖叫涉及的問題點(diǎn)更多。低速抖動(dòng)優(yōu)先查位置反饋分辨率編碼器線數(shù)低、分辨率不足速度環(huán)的反饋量化噪聲會(huì)被放大表現(xiàn)為低速時(shí)轉(zhuǎn)速忽快忽慢。高速尖叫大部分是電流環(huán)PI增益太高或者前饋解耦沒做q軸對(duì)d軸的干擾反饋成高頻噪聲。另外死區(qū)補(bǔ)償也值得檢查占空比較小時(shí)死區(qū)影響占比大噪聲尤其明顯。如果程序環(huán)里沒有做死區(qū)補(bǔ)償高速弱磁段很容易聽到刺耳的嘯叫。6.2 無感啟動(dòng)失敗的完整排查鏈路無感啟動(dòng)失敗的排查需要沿著程序環(huán)的階段一步步定位不能跳著猜。我給一個(gè)可以復(fù)現(xiàn)的排查鏈路觀測(cè)開環(huán)強(qiáng)拖階段的電流有沒有建立。如果電流沒建立說明強(qiáng)拖階段的iq_ref或虛擬角度遞增沒有生效優(yōu)先檢查狀態(tài)機(jī)是否從ALIGN正確進(jìn)到START。觀測(cè)轉(zhuǎn)子在定位階段有沒有位移。完全沒有位移就檢查定位電壓矢量的幅值和作用時(shí)間是不是不夠尤其觀察是否有負(fù)載力矩把轉(zhuǎn)子壓住了。判斷是不是失步。強(qiáng)拖過程中轉(zhuǎn)子沒跟上虛擬角度表現(xiàn)為電流逐漸增大但轉(zhuǎn)速不上升或者電機(jī)有明顯的咕嚕咕嚕聲。查看切入瞬間的切換條件。把觀測(cè)器是否收斂、轉(zhuǎn)速是否達(dá)到閾值、角度差限值是否滿足都通過通信打印出來看卡在哪一個(gè)條件。如果所有條件都滿足但仍然切換失敗重點(diǎn)檢查觀測(cè)器角度是否出現(xiàn)0度和360度之間的來回跳變這是角度換界處理沒做好。這套鏈路我每次調(diào)新板子都會(huì)走一遍能覆蓋掉九成以上的啟動(dòng)問題。6.3 中斷執(zhí)行時(shí)間的測(cè)量與優(yōu)化程序環(huán)性能最直接的指標(biāo)就是中斷執(zhí)行時(shí)間。測(cè)量方法很簡(jiǎn)單在中斷入口拉高一個(gè)GPIO出口拉低用示波器量高電平寬度。目標(biāo)值應(yīng)該小于開關(guān)周期的70%。比如20kHz開關(guān)周期是50微秒電流環(huán)執(zhí)行時(shí)間最好控制在35微秒以內(nèi)剩下30%給ADC采樣、硬件保護(hù)響應(yīng)和其他中斷留余量。如果超過了電機(jī)容易在高速大電流工況下出問題因?yàn)橹袛噙€沒算完下一次PWM事件已經(jīng)來了控制節(jié)奏被打亂。發(fā)現(xiàn)超時(shí)后優(yōu)先排查中斷里有沒有調(diào)用標(biāo)準(zhǔn)的浮點(diǎn)庫函數(shù)特別是開方、反正切、sin/cos。這些函數(shù)動(dòng)輒幾微秒非常拖時(shí)間。解決方式有幾種用查表替代三角函數(shù)用定點(diǎn)算法替代浮點(diǎn)把觀測(cè)器里非線性部分拆到慢速任務(wù)里算。凌歐框架里sin/cos和反正切都有查表版本目的就是保證中斷周期的確定性。關(guān)于無感FOC的觀測(cè)器程序環(huán)里最核心的問題是觀測(cè)器跑多快。凌歐框架的滑模觀測(cè)器在電流環(huán)中斷里同步執(zhí)行頻率和電流環(huán)一致這樣角度延遲小切入閉環(huán)時(shí)抖動(dòng)也小。但高頻執(zhí)行的代價(jià)是中端負(fù)載變大。如果你發(fā)現(xiàn)中斷時(shí)間占用率過高可以把觀測(cè)器拆開高頻部分狀態(tài)矩陣更新放中斷低頻部分角度提取PLL放慢速任務(wù)前提是相位延遲不能超出允許范圍。這個(gè)取舍要看具體電機(jī)的額定轉(zhuǎn)速轉(zhuǎn)速越高對(duì)角度延遲越敏感越不建議把觀測(cè)器拆開。最后聊聊參數(shù)在線整定的一點(diǎn)個(gè)人經(jīng)驗(yàn)。速度環(huán)PI參數(shù)和電流環(huán)PI參數(shù)是分開整定的順序一定是先電流環(huán)后速度環(huán)。電流環(huán)整定時(shí)先給一個(gè)小幅度的iq_ref階躍用示波器看iq的響應(yīng)波形調(diào)整P讓響應(yīng)達(dá)到臨界阻尼再加一點(diǎn)I消除穩(wěn)態(tài)誤差。然后整速度環(huán)同樣是看階躍響應(yīng)但速度環(huán)整定一定要在電機(jī)連續(xù)運(yùn)行時(shí)進(jìn)行而且要盯住電流是否超限。程序環(huán)里如果做了寄存器映射通信這個(gè)過程就很舒服參數(shù)在線改波形在線看不用一遍遍重新編譯燒錄。這也是我把凌歐框架程序環(huán)流程稱作血液循環(huán)系統(tǒng)的原因信號(hào)流、狀態(tài)流、數(shù)據(jù)流全部要通暢任何一環(huán)堵了整個(gè)系統(tǒng)都會(huì)立刻表現(xiàn)出不正常的癥狀。