Skip to content

TMR3109 磁編碼器全鏈路:協議、驅動、標定,以及一個"裝錯磁鐵"的坑 ​

TMR3109 是一顆 23-bit 磁旋轉編碼器,SPI 讀絕對角度,裝在夾爪手指轉軸上測開合。 從驅動、資料採集到標定,全鏈路已上線:MCU 50Hz 採集 → AP → 網頁九點分段標定。 最大的教訓不在軟體:讀數異常的頭號根因不是裝配偏心,而是裝錯了磁鐵的充磁方向。

成果速覽 ​

換掉錯誤磁鐵後,量程從"個位數~二十幾度、臺間差 10 倍"恢復到 ~40°:

能力現狀
協議解析SPI Mode 1,28-bit 幀(23-bit 角度 + CRC + error)✅
採集MCU 50Hz 採集 → 共享記憶體 → AP → 網頁/標定 ✅
標定兩點線性 + 九點分段標定共存(治具 0/5/…/40°)✅
讀數晶片角度 / 標定角度 / 開合百分比 / 量程,四種口徑 ✅
失敗模式磁鐵型別、感測器掉線、無磁鋼、量程退化——全部有判據 ✅

感測器與安裝要求 ​

TMR3109(多維科技)基於隧道磁阻:晶片測的是正上方磁場向量的方向,不是零件角度。 磁鋼隨手指轉軸旋轉,面內場向量跟隨,晶片讀出絕對角度。

原廠對安裝的硬性要求(產品規格書 §3.6):

項規格
磁鋼Ø9 × 2.5 mm,釹鐵硼 N35SH,徑向對半充磁
安裝距離(氣隙)1 ~ 3 ~ 10 mm
晶片表面場強100 ~ 1000 Gs
中心偏差≤ 0.5 mm
中心傾斜≤ ±3°

⚠️ 場強範圍兩處寫法不一致:規格書 §3.6 寫 100~1000 Gs,官網產品頁寫 200~800 Gs,建議向原廠確認。

⚠️ 頭號前提:磁鋼的充磁方向(本篇主角) ​

"徑向對半充磁"是字面意思:圓盤的 N、S 沿直徑左右分佈。 本批結構裝的是軸向充磁(一個圓面是 N、一個圓面是 S)——這就是災難的起點:

兩種充磁方向對比

驅動與資料鏈路 ​

SPI 協議與位提取 ​

讀角度指令返回 28-bit 資料(4 位元組 SPI 幀,MSB 優先):

位內容
d[27:5]23-bit 角度碼
d[4:1]4-bit CRC(x⁴+x³+x²+1,初值 0011)
d[0]error 位
c
// 换算:θ = raw / 8388608 × 360°(raw 为 23-bit 角度码)
rt_uint8_t tx[4] = {0x60, 0x00, 0x00, 0x00}, rx[4] = {0};
spi_xfer(s, tx, rx, 4);
uint32_t v = (rx[0]<<24) | (rx[1]<<16) | (rx[2]<<8) | rx[3];
uint32_t raw = (v >> 5) & 0x7FFFFF;      // d[27:5]
float angle = raw / 8388608.0f * 360.0f; // 0~360°

坑:datasheet 時序圖沒寫,但實測 MISO 有 4 個時鐘的流水線延遲—— 按手冊位對齊提取會把讀數鉗在 337.5°~360°。上程式碼已按實測修正(>>5 取 d[27:5])。

資料鏈路 ​

  • 讀數經 raw/8388608×360 換算成角度,四條路徑(MCU 序列埠 / 共享記憶體 / HTTP / 網頁)數值一致
  • 採集完整性已驗證:60s 3012 幀無丟幀、無毛刺、無位錯誤特徵

遇到的問題:同型機量程差 10 倍 ​

現象:同一結構、同一 80° 開合行程(預期感測器量程 ~40°), 本批 9 臺實測讀數量程 2.6°~25.1°,且同一側機器出現正/反兩種讀數方向。

機號量程機號量程機號量程
機125.1°機411.2°機74.5°
機213.9°機511.0°機83.8°
機311.7°機68.0°機92.6°

當時的分析走了兩條線:

教訓:"橫向偏心"模型在數學上完全自洽,也擬合了觀測,但擬合到的原因不一定是真因。 最終是結構+原廠確認才定案。排查順序應當是:先驗磁鐵充磁方向,再談裝配公差。

定案:裝錯了磁鐵 ​

軸向充磁磁鋼在晶片軸線上產生的面內旋轉分量 ≈ 0(磁場沿軸向走), 讀數只剩磁鋼偏心/晃動帶來的小殘餘分量——所以量程小、臺間差大、方向隨機翻轉。 這與觀測完全吻合;換正確磁鐵(徑向對半充磁)後,面內旋轉分量佔主導,量程立即恢復 ~40°。

快速鑑別兩種充磁(來料/裝配自檢):

方法徑向對半充磁(正確)軸向充磁(錯誤)
鐵片靠近圓盤邊緣兩側(N、S 各一半)都吸(側面是磁極面)邊緣一圈吸力弱且均勻
鐵片靠近上下圓面不吸 / 弱一面 N、一面 S 都吸(圓面就是磁極)
裝轉軸上轉一週測讀數量程正常(~40°)量程很小、不穩定、方向隨機

怎麼救殘餘非線性:兩點 + 九點分段標定 ​

兩點標定(全閉/全開)只能做線性對映,修正不了中段非線性(讀數被壓扁的曲線不是直線)。 所以在應用層加了九點分段標定:治具給出 9 個(治具角度, 原始值)點對,分段線性插值把非線性掰回來。

九點分段標定示意

兩種標定方式共存 ​

兩套資料都保留,mode 欄位決定當前生效方式(哪個後做用哪個):

你做的操作生效對映
九點「確認標定」分段線性(points)
「標定全閉/全開」兩點線性(two-point)
「啟用九點標定」按鈕顯式切回分段

操作(網頁「感測器」頁) ​

  1. 手指放到治具某卡位(如 20°)→ 點對應按鍵(採 2 秒均值)→ 重複點即覆蓋
  2. 九點齊全(9/9 已采集)→ 點「確認標定」(校驗:九點齊備 + 讀數隨角度單調)
  3. 生效後即時顯示 開合百分比(給演算法的口徑)、標定角度、量程

介面:/api/v1/angle/calib(GET/POST)、/calib/{point,commit,reset,mode}、/angle/regress。

讀數口徑(容易混) ​

顯示含義
即時晶片原始角度(0~360°)+ raw,與標定無關
標定角度raw 經當前標定換算的治具角度(0~40°),超程顯示 ⚠超程
開合raw 經當前標定換算的百分比(給演算法)
量程當前標定的量程 = span_raw / span_deg(晶片角度)

口徑坑:端點欄位(closed_deg/open_deg/span_deg)一律是晶片角度,不是治具角度—— 之前九點確認曾把治具角度寫進端點欄位,導致"量程"顯示成 40°,已統一修正。

經驗與坑檔案 ​

現象根因判據 / 解決
量程個體差異巨大、方向隨機磁鋼裝錯(軸向充磁)換徑向對半充磁;來料/裝配按規格書 §8 驗充磁方向
讀數恆為 0x7FFFFF(359.99996°)感測器未響應(未供電/未連線/掉線),MISO 上拉讀全 1真值在 360° 附近會抖 ±幾 LSB,釘死 = 假值;檢查供電與 J57 連線;驅動應補 CRC/error 位校驗
讀數滿量程隨機跳(幾 ms ±300°)無磁鋼或磁鋼不在位(裸板)這不是"噪聲大",是沒訊號;裝磁鋼
標定後百分比是天文數字兩次採在同一位置,端點量程退化已加 2000 raw 保護;在兩個真實位置重新標定
兩點面板「量程」顯示 40°治具角度被寫進端點欄位端點欄位統一為晶片角度
MSH 單跑 tmr3109 觸發斷言SPI 未單獨 init先 angle_init
部署後功能沒變構建後漏了 docker cp 產物,推的是舊二進位制用 md5 比對板上二進位制 vs 產物,必做
靜止噪聲健康整機 std ≈ 0.001°(~18 LSB)>0.5° 查機械晃動或磁場;測噪聲要直讀共享記憶體按時間戳去重,HTTP 輪詢會重複計數低估噪聲

復現與出處 ​

項位置
驅動MCU:rtos/components/angle_sensor/angle_sensor.c(SPI Mode 1,位提取含 4clk 延遲修正)
採集MCU:applications/gripper/sensor_acq.c(50Hz → 共享記憶體)
標定AP:app/gripper/v2/cmd/gripper-app/angle_calib.go、angle_calib_http.go、web/index.html
資料手冊多維科技 TMR3109 產品規格書 v1.0.1(§3.6 磁場規格、§4.1 SPI、§8 機械角度方向)
知識庫團隊 skill:magnetic-angle-sensor、rv1126b-gripper-angle-calib

寫於 2026-09 · 基於夾爪專案實測 · 全部資料來自真機

這篇裡有不清楚的地方,或者想聊類似的東西?私訊我 →