控制實踐)
簡介這是一份面向電子設(shè)計競賽選手與嵌入式控制學(xué)習(xí)者的自由擺平板控制系統(tǒng)設(shè)計文檔圍繞如何在擺桿擺動過程中保持末端平板水平這一動態(tài)控制問題展開。方案以STM32F103VET6為控制核心配合TFT液晶顯示、高精度WDD35D4導(dǎo)電塑料角位移傳感器與四宏細分驅(qū)動器驅(qū)動的步進電機通過A/D采樣實時獲取擺桿與平板角度并閉環(huán)調(diào)節(jié)轉(zhuǎn)向與轉(zhuǎn)角實現(xiàn)硬幣相對靜止、激光筆命中接收靶等題目要求。文中還完整比較了控制器、角度檢測、電機與電源四類模塊的備選方案及取舍理由并給出擺架框架、檢測系統(tǒng)與控制驅(qū)動系統(tǒng)三部分的結(jié)構(gòu)劃分。壓縮包內(nèi)為1個docx文檔約36KB已積累308人學(xué)習(xí)下載適合用于課程設(shè)計、競賽復(fù)盤或嵌入式動態(tài)控制方案參考。1. 需求先立住自由擺平板控制在控制什么、誤差窗口有多窄自由擺的控制系統(tǒng)題目念起來一句話做起來是一串連鎖反應(yīng)擺桿靠重力自由擺動末端平板上放一枚硬幣要求整個擺動過程硬幣不滑落發(fā)揮部分還要讓平板上的激光筆始終打在接收靶上。控制目標就變成了——擺桿角每變化一度平板都得反向補回去工程上能接受的誤差窗口通常只有 ±1.5°再大硬幣就開始挪位置了。這套東西適合機電一體化、自動化、嵌入式方向的課程設(shè)計和畢業(yè)設(shè)計因為它把角位移傳感器、A/D 采樣、步進驅(qū)動、機械間隙、閉環(huán)控制串成一條完整鏈路哪一環(huán)虛了硬幣會當(dāng)場提醒你。下面按我實際搭的順序從選型講到驗收。2. 總體架構(gòu)與選型三層結(jié)構(gòu)、四組方案對比與引腳分配2.1 擺架、檢測、驅(qū)動三層結(jié)構(gòu)各自負責(zé)什么整個系統(tǒng)按物理功能切成三層后面所有代碼和接線都掛在這三層上不要混著做。擺架框架層是被控對象本身擺架座、擺桿、軸承、末端電機座平板固定在電機軸上。這一層的機械質(zhì)量直接決定后面算法的上限——軸承有曠量、平板配重偏心、擺桿剛度不夠再好的控制律也壓不住抖動通常的做法是先把擺桿擺動一次看自由衰減正常應(yīng)該平順衰減如果出現(xiàn)周期性的頓或者異響先修機械再寫代碼。檢測層負責(zé)把機械狀態(tài)變成數(shù)字一組 WDD35D4 導(dǎo)電塑料角位移傳感器測擺桿角另一組裝在平板轉(zhuǎn)軸上測平板相對擺桿的轉(zhuǎn)角兩路信號經(jīng)分壓后進 STM32 的 A/D采樣值經(jīng)過濾波和標定換算成角度值。驅(qū)動層是執(zhí)行端STM32 輸出脈沖和方向信號經(jīng)四宏細分驅(qū)動器放大后帶動步進電機電機軸直接或經(jīng)一級減速帶動平板轉(zhuǎn)動。電源從 12V 電池進來一路走 LM2576 開關(guān)降壓供大電流負載一路走 L7805 線性穩(wěn)壓供傳感器和顯示再經(jīng) 3.3V LDO 給主控。層級組成交付物常見失誤擺架框架底座、擺桿、軸承、電機座、平板自由擺動周期、機械零點配重偏心導(dǎo)致靜差檢測系統(tǒng)WDD35D4 × 2、分壓網(wǎng)絡(luò)、RC 濾波角度值度、采樣率采樣窗口太短讀數(shù)跳控制驅(qū)動STM32、四宏驅(qū)動器、步進電機步數(shù)指令、轉(zhuǎn)向細分與電流檔位不匹配這個分層的價值在于排查硬幣掉了先看角度顯示準不準檢測層再看電機聽不聽話驅(qū)動層最后才懷疑算法。2.2 四組方案的取舍主控、傳感器、執(zhí)行器、電源主控51 還是 STM32。51 便宜、資料多但運算速度慢、片內(nèi)資源少跑兩路 A/D 加濾波加閉環(huán)再加液晶刷新會很吃力。選 STM32F103VET6 的理由很實際Cortex-M3 內(nèi)核主頻夠用庫函數(shù)開發(fā)門檻低片內(nèi)多通道 ADC 配合 DMA 可以直接把采樣搬進內(nèi)存不占 CPU功耗也低。有個細節(jié)要澄清——不少資料寫它8 通道 10 位 ADC實際 F103 系列是 12 位逐次逼近型配置時按 12 位寫需要粗分辨率就右移取高位別被這句話帶偏把精度白白丟掉。角度檢測電位器、ADXL345 還是 WDD35D4。普通電位器線性度差角度誤差太大壓不住 ±1.5° 的窗口ADXL345 是基于重力加速度分量算傾角靜態(tài)測傾沒問題但自由擺是動態(tài)過程擺桿的切向加速度會直接污染讀數(shù)擺得越快錯得越離譜。WDD35D4 是導(dǎo)電塑料角位移傳感器本質(zhì)是精密電位器輸出與轉(zhuǎn)角成線性關(guān)系的電阻精度高、響應(yīng)快、不怕動態(tài)加速度代價是需要一個穩(wěn)定的激勵電壓和一次認真的標定。執(zhí)行器伺服還是步進。伺服性能好、能高速制動、慣量小但價格高對課設(shè)/畢設(shè)預(yù)算不友好。步進電機脈沖驅(qū)動、開環(huán)定位精度夠用配合 16 細分能明顯減弱低頻振動控制邏輯簡單。代價是丟步不可自察所以必須靠角度傳感器構(gòu)成半閉環(huán)來兜底。電源鉛酸直供還是多級變換。鉛酸電池電流大但太重整機結(jié)構(gòu)會變笨。最終走 12V 電池 多級變換大電流支路用 LM2576 開關(guān)降壓效率高、發(fā)熱小傳感器激勵和運放用 L7805 線性穩(wěn)壓紋波小、噪聲低。這里別圖省事全用線性穩(wěn)壓12V 降到 5V 壓差 7V幾百毫安就是一兩瓦的發(fā)熱夏天能把板子烤到燙手。對比項方案 A方案 B方案 C選擇主控51 單片機STM32F103VET6—B角度檢測普通電位器ADXL345WDD35D4C執(zhí)行器伺服電機步進電機 細分驅(qū)動—B電源鉛酸直供12V L7805/LM2576 多級變換—B2.3 外設(shè)資源分配與系統(tǒng)初始化骨架選型定下來之后第一件事是分引腳分完再畫板、再寫代碼避免中途改線。下面這份分配表可以照著改具體以手里板子的實際絲印為準。功能外設(shè)資源引腳說明擺桿角采樣ADC1_IN0PA0WDD35D4 分壓輸出平板角采樣ADC1_IN1PA1同上電池電壓檢測ADC1_IN2PA212V 經(jīng)電阻分壓到 3.3V 內(nèi)步進脈沖 STEPTIM1_CH1PA8每周期翻轉(zhuǎn)一次產(chǎn)生一個脈沖步進方向 DIRGPIO 推挽PB0高電平正轉(zhuǎn)驅(qū)動器使能 ENAGPIO 推挽PB1低有效上電先拉高再釋放TFT 液晶SPI1PA5/PA6/PA7片選 PA4僅刷數(shù)字區(qū)域調(diào)試串口USART1PA9/PA10上位機看角度曲線初始化順序有講究先時鐘、再 GPIO、再 ADC 校準、最后開定時器。ADC 校準必須在使能轉(zhuǎn)換之前做否則前幾十次采樣值整體偏移很多人以為是傳感器壞了。/* 系統(tǒng)啟動骨架順序不能亂尤其 ADC 校準要在啟動轉(zhuǎn)換之前 */ int main(void) { SystemInit(); /* 72MHz 主頻 */ Delay_Init(); /* SysTick 延時基準 */ GPIO_Config(); /* DIR / ENA / LED / 按鍵 */ USART1_Config(115200); /* 調(diào)試串口 */ TFT_Init(); /* 液晶屏先清屏再畫框架 */ AngleAdc_Init(); /* 雙通道 ADC DMA內(nèi)部含校準 */ Stepper_Init(); /* TIM1 脈沖定時器先不使能 */ Stepper_Enable(1); /* 釋放驅(qū)動器電機抱死 */ LCD_DrawFrame(); /* 靜態(tài)框架只畫一次后面只刷數(shù)字 */ while (1) { Control_Loop(); /* 5ms 周期控制 */ if (g_lcd_cnt 20) { /* 100ms 刷一次顯示別每周期刷 */ g_lcd_cnt 0; LCD_Refresh(); } Delay_ms(5); } }這里有個容易被忽略的點液晶刷新和控制在同一個循環(huán)里如果每個控制周期都刷屏SPI 寫屏的時間會把控制周期拉長到幾十毫秒擺桿動得快的時候補償就跟不上了。顯示只刷變化的數(shù)字區(qū)域靜態(tài)框架上電畫一次控制周期才能穩(wěn)住。2.4 控制周期與時間預(yù)算控制周期定 5ms對應(yīng) 200Hz。這個數(shù)字不是拍腦袋自由擺的擺動周期一般在 1~2 秒量級按 200Hz 采樣一個周期內(nèi)有幾百個采樣點相位滯后可以接受再快也沒意義因為步進電機的響應(yīng)跟不到那么細。時間預(yù)算要算清楚5ms 里兩路 ADC 轉(zhuǎn)換耗時12 位、239.5 周期采樣時間單次約 21μs兩通道約 42μs可以忽略中值濾波 8 點排序加角度解算大約幾十微秒剩下的幾乎全留給脈沖輸出和液晶。所以液晶必須降頻到 100ms串口打印更要壓縮調(diào)試時只在需要的時候打一次。3. 角度檢測與信號鏈WDD35D4 從分壓到角度值的完整換算3.1 接線與分壓網(wǎng)絡(luò)別把 5V 輸出直接懟進 3.3V 的 ADCWDD35D4 是三線制兩端接激勵電壓中間抽頭輸出電壓。抽頭電壓與轉(zhuǎn)角在一定電氣角范圍內(nèi)成線性關(guān)系。接線要遵守兩條第一激勵電壓必須是穩(wěn)定的基準不能直接拿電機電源或者電池裸電壓當(dāng)激勵。電池從 12.6V 掉到 11V分壓比跟著變角度讀數(shù)就整體漂這屬于典型的上電準、跑一會兒不準。第二抽頭輸出幅度必須落在 0~3.3V 之內(nèi)。如果激勵用 5V滿量程輸出接近 5V直接進 STM32 的 ADC 會打壞輸入保護二極管。通常的做法是激勵也用 3.3V或者在抽頭后面加一級電阻分壓把幅度壓到 3.0V 以內(nèi)再用電壓跟隨器做阻抗緩沖。傳感器輸出阻抗不低幾 kΩ 量級后面直接接 ADC 采樣電容等效就是 RC 充電。所以抽頭到 ADC 之間串 1kΩ、對地并 0.1μF構(gòu)成截止頻率約 1.6kHz 的低通既能濾掉電機干擾又不至于把動態(tài)信號拖慢。提示分壓電阻用 1% 金屬膜兩個通道用同一批次的電阻否則兩路的角度斜率不一致后面對比擺桿角和平板角時會出現(xiàn)固定偏差。3.2 ADC 采樣配置與 DMA 雙通道循環(huán)搬運兩路角度必須同步采樣否則算絕對傾角 擺桿角 平板相對角時兩個角來自不同時刻誤差會直接進閉環(huán)。用 ADC1 的掃描模式加 DMA 循環(huán)搬運兩通道在同一個轉(zhuǎn)換序列里連續(xù)轉(zhuǎn)完時間差只有二十幾微秒可以認為同步。/* 雙通道 ADC1 規(guī)則組 DMA1 循環(huán)搬運CH0 擺桿角CH1 平板角 */ #define ANG_ADC_CH_NUM 2 static volatile uint16_t adc_raw[ANG_ADC_CH_NUM]; void AngleAdc_Init(void) { GPIO_InitTypeDef gpio; ADC_InitTypeDef adc; DMA_InitTypeDef dma; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); /* 模擬輸入模式禁止上下拉否則外部下拉會把分壓比帶偏 */ gpio.GPIO_Pin GPIO_Pin_0 | GPIO_Pin_1; gpio.GPIO_Mode GPIO_Mode_AIN; GPIO_Init(GPIOA, gpio); DMA_DeInit(DMA1_Channel1); dma.DMA_PeripheralBaseAddr (uint32_t)ADC1-DR; dma.DMA_MemoryBaseAddr (uint32_t)adc_raw; dma.DMA_DIR DMA_DIR_PeripheralSRC; dma.DMA_BufferSize ANG_ADC_CH_NUM; dma.DMA_PeripheralInc DMA_PeripheralInc_Disable; dma.DMA_MemoryInc DMA_MemoryInc_Enable; dma.DMA_PeripheralDataSize DMA_PeripheralDataSize_HalfWord; dma.DMA_MemoryDataSize DMA_MemoryDataSize_HalfWord; dma.DMA_Mode DMA_Mode_Circular; /* 循環(huán)模式CPU 隨時取最新值 */ DMA_Init(DMA1_Channel1, dma); DMA_Cmd(DMA1_Channel1, ENABLE); ADC_DeInit(ADC1); adc.ADC_Mode ADC_Mode_Independent; adc.ADC_ScanConvMode ENABLE; /* 雙通道掃描 */ adc.ADC_ContinuousConvMode ENABLE; /* 連續(xù)轉(zhuǎn)換DMA 自己搬 */ adc.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; adc.ADC_DataAlign ADC_DataAlign_Right; adc.ADC_NbrOfChannel ANG_ADC_CH_NUM; ADC_Init(ADC1, adc); /* 傳感器輸出阻抗高采樣窗口取最長檔短窗口必然讀不準 */ ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); /* 上電校準必須在使能轉(zhuǎn)換之前完成否則前若干次采樣整體偏移 */ ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1)); ADC_SoftwareStartConvCmd(ADC1, ENABLE); }采樣時間選 239.5 周期不是隨手寫的ADC 時鐘按 12MHz 算一次轉(zhuǎn)換約 (239.512.5)/12MHz ≈ 21μs兩通道 42μs相對 5ms 控制周期占比不到 1%。有人為了提高采樣率把它改成 1.5 周期結(jié)果讀數(shù)隨電機轉(zhuǎn)速亂跳原因就是采樣電容還沒充到傳感器輸出電壓就關(guān)門采樣了。3.3 中值濾波、兩點標定與角度解算從 ADC 值到角度值要做兩件事去野值、建映射。去野值用中值濾波而不是簡單平均。電機換向、驅(qū)動器斬波會在模擬通道上打出一兩個明顯偏離的采樣點平均值會把這顆老鼠屎攤到整個結(jié)果里中值濾波直接把它篩掉。/* 8 點采樣排序后取中間 4 點平均既濾脈沖干擾又保留一點平滑 */ static uint16_t Median4(uint16_t *buf, uint8_t n) { uint8_t i, j; uint16_t tmp; for (i 0; i n - 1; i) { /* 冒泡排序n 只有 8開銷可忽略 */ for (j 0; j n - 1 - i; j) { if (buf[j] buf[j 1]) { tmp buf[j]; buf[j] buf[j 1]; buf[j 1] tmp; } } } return (uint16_t)((buf[2] buf[3] buf[4] buf[5]) 2); }標定用兩點法把機構(gòu)裝好、傳感器裝好之后再標不要在臺面上拿手轉(zhuǎn)著標——裝上去之后機械零位就變了。做法是把平板擺到兩個已知角度比如 -30° 和 30°用量角器或者水平儀確認分別記錄 ADC 值解出斜率和截距。typedef struct { float k; /* 斜率度 / LSB */ float b; /* 截距度 */ float limit_l; /* 機械下限防算出離譜值 */ float limit_h; /* 機械上限 */ } AngleCal_t; static AngleCal_t cal_rod {0.0f, 0.0f, -70.0f, 70.0f}; static AngleCal_t cal_plate {0.0f, 0.0f, -95.0f, 95.0f}; /* 兩點標定adc_a/adc_b 是實測 ADC 均值deg_a/deg_b 是對應(yīng)角度 */ void AngleCal_TwoPoint(AngleCal_t *cal, float adc_a, float deg_a, float adc_b, float deg_b) { cal-k (deg_b - deg_a) / (adc_b - adc_a); cal-b deg_a - cal-k * adc_a; } float Angle_Read(const AngleCal_t *cal, uint16_t raw) { float deg cal-k * (float)raw cal-b; if (deg cal-limit_l) deg cal-limit_l; if (deg cal-limit_h) deg cal-limit_h; return deg; }截距的意義是把機械水平和電信號零點對齊。這兩個零點通常不重合傳感器裝上去必然帶幾度的安裝偏差靠標定吃掉它比在結(jié)構(gòu)上硬調(diào)省事得多。斜率的意義是分辨率12 位 ADC、3.3V 基準、傳感器電氣角 340° 左右理論上每 LSB 約 0.08°比步進電機 16 細分后的 0.1125°/步還細夠用。3.4 為什么必須裝兩個傳感器擺桿角和平板角的物理關(guān)系這是整套設(shè)計里最容易想錯的地方。平板轉(zhuǎn)軸上那組傳感器測的是平板相對擺桿的轉(zhuǎn)角不是平板相對水平面的傾角。擺桿自己也在轉(zhuǎn)所以平板的絕對傾角等于兩者之和絕對傾角 擺桿角 平板相對角題目要求的平板始終保持水平翻譯成控制目標就是不管擺桿轉(zhuǎn)到哪讓絕對傾角等于 0也就是平板相對角要等于負的擺桿角。發(fā)揮部分要求激光打靶靶點位置由絕對傾角決定目標就變成讓絕對傾角等于某個固定值。如果只裝一組傳感器只測平板相對角把目標設(shè)成 0看起來平板水平了實際上它只是相對擺桿水平擺桿一歪硬幣立刻滑。這是我在調(diào)試階段見過的翻車現(xiàn)場里最典型的一個顯示一切正常硬幣每次都在擺到最高點時掉下去。4. 執(zhí)行機構(gòu)與驅(qū)動四宏細分驅(qū)動器、脈沖發(fā)生與位置環(huán)落地4.1 驅(qū)動器接線、細分與電流檔位四宏細分驅(qū)動器一般有六根控制端子PUL、PUL-、DIR、DIR-、ENA、ENA-加上四根電機相線。STM32 是 3.3V 電平直接把脈沖腳接 PUL、PUL- 接單片機地驅(qū)動器內(nèi)部光耦就能正常導(dǎo)通如果現(xiàn)場干擾大脈沖和方向都加一級高速光耦隔離代價是延遲增加幾微秒對 2kHz 以內(nèi)的脈沖完全無影響。細分檔位通過撥碼設(shè)置檔位和單步角度的對應(yīng)關(guān)系如下按 1.8° 兩相混合式步進電機算細分檔位每轉(zhuǎn)脈沖數(shù)單步角度適用場景整步2001.8°只做粗定位噪聲大半步4000.9°低成本場合4 細分8000.45°中速跟蹤8 細分16000.225°常用檔位16 細分32000.1125°本項目選擇選 16 細分是為了壓低頻振動——步進電機整步運行在低速段會有明顯的咯噔感這個振動會通過擺桿傳到傳感器上被當(dāng)成角度波動采進來形成自激。但細分不是越高越好細分越高單脈沖轉(zhuǎn)矩越小電流檔位如果還按整步的設(shè)電機就會出現(xiàn)聽著在轉(zhuǎn)、實際沒動的丟步。電流檔位按電機銘牌額定電流設(shè)寧可比額定略高一檔別低。4.2 脈沖發(fā)生與梯形加減速脈沖用定時器更新中斷翻轉(zhuǎn) IO 產(chǎn)生比 PWM 方式更靈活因為頻率要隨剩余步數(shù)動態(tài)改。定時器預(yù)分頻到 1MHz 計數(shù)ARR 決定脈沖頻率ARR499 對應(yīng) 2kHz約 225°/sARR1999 對應(yīng) 500Hz約 56°/s作為起步頻率。/* TIM2 更新中斷每次中斷翻轉(zhuǎn) STEP 引腳ARR 決定當(dāng)前轉(zhuǎn)速 */ static volatile int32_t step_remain 0; /* 剩余脈沖數(shù)正為正向負為反向 */ #define STEP_ARR_FAST 499 /* 高速檔約 2kHz */ #define STEP_ARR_SLOW 1999 /* 起步/到位檔約 500Hz */ void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) ! RESET) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); if (step_remain 0) { /* 走完就關(guān)定時器避免空轉(zhuǎn)發(fā)熱 */ TIM_Cmd(TIM2, DISABLE); return; } /* 翻轉(zhuǎn) STEP 引腳一個完整脈沖需要一個高電平加一個低電平 */ GPIO_WriteBit(GPIOA, GPIO_Pin_8, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_8))); if (step_remain 0) step_remain--; else step_remain; /* 簡化的梯形策略剩余步數(shù)多時提速快到位時降速防止沖過頭 */ int32_t abs_remain (step_remain 0) ? step_remain : -step_remain; TIM_SetAutoreload(TIM2, (abs_remain 40) ? STEP_ARR_FAST : STEP_ARR_SLOW); } } /* 上層調(diào)用設(shè)定方向后啟動脈沖非阻塞主循環(huán)繼續(xù)跑 */ void Stepper_Move(int32_t steps) { if (steps 0) return; if (steps 0) GPIO_ResetBits(GPIOB, GPIO_Pin_0); /* DIR 低 正向 */ else GPIO_SetBits(GPIOB, GPIO_Pin_0); TIM_Cmd(TIM2, DISABLE); step_remain (steps 0) ? steps : -steps; TIM_SetAutoreload(TIM2, STEP_ARR_SLOW); /* 一律從慢速起步 */ TIM_SetCounter(TIM2, 0); TIM_Cmd(TIM2, ENABLE); }這段代碼的關(guān)鍵在非阻塞三個字設(shè)定好剩余步數(shù)就返回主循環(huán)不用等電機走完5ms 后繼續(xù)算下一個控制量。如果改成死等走完控制周期會被拉長到幾十毫秒擺動過程中補償就跟不上了。方向腳在啟動前設(shè)好因為 DIR 信號需要提前脈沖至少幾微秒建立中途切換方向容易丟步。4.3 從角度誤差到步數(shù)的位置環(huán)步進電機本身是開環(huán)的但有了角度傳感器就有了反饋構(gòu)成一個半閉環(huán)位置環(huán)。最簡的形式是比例控制每個控制周期讀一次絕對傾角算出和目標角的誤差乘以系數(shù)換成步數(shù)下發(fā)給電機。系數(shù)怎么定16 細分下平板直連時每步 0.1125°也就是 1° 誤差對應(yīng)約 8.9 步。如果中間加了 1:3 減速帶平板轉(zhuǎn) 1° 電機要轉(zhuǎn) 3°系數(shù)就是 26.7。#define PLATE_KP 8.9f /* 步/度直連時約 1/0.1125有減速比要乘 */ #define PLATE_DEAD_ZONE_DEG 0.15f /* 死區(qū)小于它不動防止來回點頭 */ #define STEP_MAX_PER_CYCLE 10 /* 單周期限幅 5ms × 2kHz */ /* 輸入絕對傾角與目標絕對傾角輸出本周期要走的步數(shù)帶方向 */ int32_t Plate_ControlOnce(float abs_plate_deg, float target_deg) { float err target_deg - abs_plate_deg; /* 死區(qū)誤差極小時不動作機械回差會讓它反復(fù)來回 */ if (err -PLATE_DEAD_ZONE_DEG err PLATE_DEAD_ZONE_DEG) return 0; int32_t steps (int32_t)(err * PLATE_KP); /* 限幅一個周期內(nèi)電機最多能走的步數(shù)超了也發(fā)不出去 */ if (steps STEP_MAX_PER_CYCLE) steps STEP_MAX_PER_CYCLE; if (steps -STEP_MAX_PER_CYCLE) steps -STEP_MAX_PER_CYCLE; return steps; }限幅值不是隨便填的控制周期 5ms脈沖頻率上限 2kHz5ms 內(nèi)最多只能發(fā) 10 個脈沖所以單周期步數(shù)上限就是 10。很多人把 Kp 調(diào)得很大算出幾十步程序里又照發(fā)不誤結(jié)果定時器隊列積壓電機一直走停走??雌饋硐窨D其實是限幅沒做。4.4 軟限位、回零與機械回差補償步進電機是開環(huán)的一旦丟步位置就永久偏了所以必須有兜底軟限位——角度超出機械安全范圍時立即停脈沖并反向。這個判斷放在控制周期里比放在中斷里安全?;亓恪想姇r先朝一個方向慢速轉(zhuǎn)撞到機械擋塊或者觸發(fā)光電開關(guān)就停把當(dāng)前位置記為零點再反向退回一個小角度。沒有回零流程的系統(tǒng)每次上電零點都不一樣標定參數(shù)就白標了?;夭钛a償——齒輪或聯(lián)軸器有間隙正向到位和反向到位差那么一兩度。通常的做法是恒定單向逼近無論目標在上還是在下都先多走 2~3 步再反向退回來讓齒面始終在同一側(cè)接觸。這個技巧很土但極其有效能把到位抖動壓掉一大半。5. 常見問題排查采樣跳變、電機丟步與到位抖動的五類現(xiàn)場故障5.1 角度讀數(shù)在靜止時上下跳 ±2°現(xiàn)象擺桿不動液晶上的角度值在 ±2° 范圍內(nèi)亂跳電機跟著小幅度來回修正。原因三個常見來源——采樣時間設(shè)得太短ADC 采樣電容沒充滿、傳感器輸出沒有阻抗緩沖幾 kΩ 的輸出阻抗直接驅(qū)動采樣保持電路、模擬地和數(shù)字地混在一起電機電流在地線上的壓降被采進來了。解決采樣時間改到 239.5 周期抽頭后加電壓跟隨器或者至少串 1kΩ 并 0.1μF模擬地單獨走一根線回電源地別和電機地共用一段銅皮軟件上 8 點中值加均值再上一道。5.2 電機一轉(zhuǎn)角度讀數(shù)就漂現(xiàn)象電機靜止時讀數(shù)是穩(wěn)的一旦開始走脈沖角度值立刻抖而且抖的幅度跟轉(zhuǎn)速相關(guān)。原因脈沖信號線和傳感器信號線捆在一起走驅(qū)動器斬波產(chǎn)生的高頻干擾通過線間電容耦合進模擬通道或者驅(qū)動器與主控共地但接地點選在驅(qū)動器側(cè)地電流繞了一大圈回到單片機。解決脈沖線、電機相線走一側(cè)傳感器線走另一側(cè)交叉處垂直過脈沖和方向加光耦隔離模擬部分單獨 LDO 供電。做完這三條抖動基本能壓到 0.2° 以內(nèi)。5.3 平板到位后來回點頭現(xiàn)象誤差已經(jīng)很小了電機還在走兩步退兩步平板在原地小幅抖動硬幣反而更容易滑。原因死區(qū)設(shè)得太小或者干脆沒設(shè)比例系數(shù)偏大加上機械回差形成極限環(huán)。解決先加 0.1~0.2° 死區(qū)再把 Kp 降一檔觀察最后上單向逼近策略多走 2~3 步再倒退到位讓齒面始終單側(cè)接觸。這三步按順序做不要一次性全改否則不知道是哪一步起的作用。注意死區(qū)不是越大越好。死區(qū)太大平板在小角度擺動時會鈍硬幣在低幅擺動階段更容易滑通常 0.15° 是個比較平衡的值具體還要按機械剛性微調(diào)。5.4 擺動快的時候電機丟步現(xiàn)象慢速擺動時一切正常擺幅加大后平板明顯跟不上角度誤差越來越大停下來看位置已經(jīng)偏了。原因起步頻率太高直接從 2kHz 起振電機來不及跟上、細分調(diào)得太高但電流檔位沒同步調(diào)大、加減速策略缺失。解決一律從 500Hz 起步剩余步數(shù)大于 40 時才切高速檔電流檔位按電機銘牌額定值設(shè)置不要為了省電往低調(diào)擺動幅度大的場景把單周期限幅適當(dāng)放大讓電機有足夠的行程追趕。5.5 上電后零點每次都不同現(xiàn)象同一臺設(shè)備第一次上電平板是水平的重啟之后角度顯示偏了好幾度前面標定的參數(shù)像失效了一樣。原因沒有回零流程每次上電電機軸停的位置是隨機的或者標定時用的是臺面手轉(zhuǎn)的角度裝機之后機械零位已經(jīng)變了。解決加上電回零慢速撞擋塊或光電開關(guān)把回零位置寫進零點變量標定必須在整機裝配完成后進行標完把 k、b 兩個值寫進 Flash掉電不丟如果電池電壓波動大激勵源別用電池裸電壓用 LDO 穩(wěn)壓后的 3.3V。6. 驗收與答辯指標復(fù)現(xiàn)清單和演示腳本的走位驗收這一步評委看的不是你講了多少控制理論而是幾個可復(fù)現(xiàn)的動作能不能穩(wěn)定做出來。我一般會提前準備一張指標表每項都寫清測試方法和合格判據(jù)現(xiàn)場按表走不臨場發(fā)揮。驗收項測試方法合格判據(jù)平板水平保持擺桿從 60° 釋放全程記錄絕對傾角擺動全程偏差 ≤ ±1.5°硬幣實驗平板上放一枚硬幣連續(xù)擺動 10 個周期硬幣不滑落、不位移超過 5mm階躍響應(yīng)目標角從 0° 跳到 20°記錄響應(yīng)曲線300ms 內(nèi)進入 ±1° 死區(qū)超調(diào) ≤ 3°激光打靶目標點固定在 1m 外讀光點位置偏移 ≤ 2cm重復(fù) 5 次一致回零一致性連續(xù)上電 5 次記錄回零后角度讀數(shù)極差 ≤ 0.5°續(xù)航滿電連續(xù)運行滿足演示全程無異常復(fù)位答辯的演示順序很關(guān)鍵別一上來就放大招。先做靜態(tài)平板在靜止狀態(tài)下設(shè)定 0°、15°、-15°讓評委看清角度顯示和執(zhí)行的一致性再做慢速小擺幅證明閉環(huán)是穩(wěn)的最后才做滿幅擺動加硬幣。這個順序的好處是萬一滿幅階段出問題前面的基礎(chǔ)分已經(jīng)拿到了。現(xiàn)場還有兩個細節(jié)值得提前準備。一是把調(diào)試串口接出來用上位機實時畫角度曲線評委問你怎么知道誤差是多少的時候曲線比嘴說有用得多。二是準備一份失敗預(yù)案如果硬幣掉了別急著撿起來重來先說清掉在哪、為什么掉是限幅不夠還是死區(qū)偏大然后當(dāng)場改一個參數(shù)重做一次——能當(dāng)場定位并修好比一次成功更能說明你真的懂這套系統(tǒng)。有次調(diào)試我把死區(qū)從 0.15° 調(diào)到 0.05°想著響應(yīng)更快結(jié)果整個演示過程平板一直在原地小幅抖動硬幣在第三次擺動時就滑到邊上了臺下看著像系統(tǒng)不穩(wěn)定其實是參數(shù)自己給自己挖的坑。從那以后我每次改控制參數(shù)都強制走一遍靜態(tài)—小擺幅—滿幅三段驗證任何一段不過就不往下走。希望幫到你。本文還有配套的精品資源點擊獲取