# 答 sandal 刀庫應用編碼器溢位
[TOC]
建議先看猜測問題發生原因。
# 情況描述
> 我們是用海德漢Endat (單圈13bit,多圈12bit)
我曲線測試是用TS5700(單23bit 多16bit)去測試,我沒有海德漢馬達,那時是另一位同事測試,沒有留圖。
>
>我懷疑是Endat整個加起來25bit,上位跟驅動器拿的是0x6064(32bit),溢位時下次重新開機0x6064就整個錯誤。
>
>開啟ABS_MUTI,測試多圈數往負方向移動時,超過0,會從UINT32_MAX開始減少。但重新開機時,圈數變成52010範圍內。這可能導致0x6064出現問題。
>
>以上是我的想法。
> 刀庫 不是用PP 是CSP
一般用CSV 控制時,是讀0x6064的值做回授。所以要做到0x6064可以接收到改動。
## 訊息整理
* abs encoder type
* TS5700 tamagawa Tformat
* 海德漢 endat
首先是幾個事實
* encoder underflow 時,
* actual position 不明原因的跳變
* 在 encoder 沒跳,也沒有actual position 也沒有over, or under flow的時候.
* 坤宗也不知。
* abs encoder 的值確實在開機前後如遇期的truncate
* 見圖,關機前,關機後。 65831--> 295 (65831-65535=296)
*
# 找code處
刀庫的應用上更像是 Turn Table ,只是週期不再是pulse per revolution,而是pulse per track cycle。
turn table 相關集中在 `MotionControl` 的 `PositionMonitor28335`, `PositionModeControl28335`, `SetRotaryRange28335`, `SetTurntableStation28335`,
下面一些 `GetCANNPosStatusWord28335`,其它module 可以得到此 module 資料,本module 和cia402應該蠻有關的。
台中是開 profile position (PP mode),做刀庫。
可參考 `MotionProfile.h` 的 `PPCTRLWORD` 。 在整份code 裡,有在 `UpdatePosSet` ,和各個profile type 裡的 entry 。 Profile 會在 `ProfileExecute` 裡執行。而 `ProfileExecute` 會在 `PositionModeControl28335` 被 call。
`ProfileExecute` 應該是控制要執行 PP mode 的那一個(下一個)block。並且有產生每一瞬間的位置,case `PROFILE_STAGE_EXECUTE`:`ExecuteLinear`。
建議controlword 選relative mode,這樣target position 才是增量的。
profile 的implement 是那種在database裡寫死的array
`_SetNextTask28335` called by `_SetNextTask` called by `UpdatePosSet` called by `SetPosCtrl` called by `PosFunction` called by `PositionModeControl28335` in `BLOCK_MODE` case. 這個應該就是指PP mode。
`PosFunction` 幾乎全部都是 `SetPosCtrl` ,所以這個function 應該也是流程控制相關的,第一次規劃完後就不再工作。
>注意下方還有 `PROFILE_VELOCITY` (PV mode)。雖然PV mode 應該和position 毫無關係。
`ModifyPosition` 有relative 的 position implement,
```c=477
if(pTask->cw.b.mode == RELATIVE) /* relative position */
{
pThis->lPos = pThis->lSetPos;
if(pThis->nLast != -1)
pThis->lAbsPos = pLast->lAbsPos + pThis->lSetPos;
else
pThis->lAbsPos = PosCtrl.lPosTarget + pThis->lSetPos;
}
else if(pTask->cw.b.mode == ABSOLUTE)
```
可以看出 `lSetPos` 應該是主要的user input。`_SetTargetPos28335` called by `_SetTargetPos` called by `SetPosTargetPos1` in DB 也驗證這點。
大致上說,我覺得上面這段code 是有一點問題的,但不至於頻繁發生。當AbsPos 是 接近 64bit 上下限時,必須要reset,否則溢位。
不太可能常發生的原因在於已經是64bit,且為有sign
另一個可能出現的問題在於,position loop 和 encoder feedback,如果 絕對型 encoder 的feedback 值沒有做reset 或,取其相對值之類的動作,就會可能產生bug,尚未看該部份。
# 猜測問題發生原因
目前還沒辦法確定發生當下在那一環出問題。但是綜合所有資訊,我們認為最可能發生的原因如下。由於問題的描述是,當絕對型編碼器溢位的當下,不會跳任何 error,接下來的工作也是正常的。問題是當關機之後再開,機器發生誤會自己的位置。 這比較可能的現象是,由於 `lAbsPos` 有64bit>> 絕對型編碼器精度(assume 65535(16bit)),當encoder溢位發生時,由於 `lAbsPos` 有64bit,且驅動器設定為relative mode, 所以只需要知道差值,應該是有做相關處理 e.g. 上1tick 是65532 這一個tick 是5,差值大於10000(hyper parameter),所以差值是 5-65532+65535=8。`lAbsPos` 則會記錄為65532+8=65540
假設此時突然斷電。
但是當斷電再開後,不論驅動器是否記錄 65540,因為驅動器不會知道關機狀態下,馬達有沒有移動,所以都要從encoder 重新讀值(絕對值編碼器的意義),並視此值為絕對位置(絕對值編碼器),所以`lAbsPos`會被設為5。
以下再假設刀庫跑一個cycle 是 800 。斷電前真實所在的位置就是65540%800=740。然後斷電後,卻變成5,所以我們觀察者會認為位置跑掉。除非編碼器的溢位值,剛好是刀庫cycle的倍數 e.g. 771。 65540%771=5 (same)
## 標準的解法
我們要分析一下絕對值編碼器和增量型編碼器有何應用上的差異。一般來說,絕對型編碼器會被用在範圍有距離極限的工況,比如CNC的單軸。旋轉的case 則是手臂,此時手臂的旋轉角度也是有極限的比如+-3圈。
相反的是,增量型編碼器常被用在**無限循環**之類的工況,比如單向不間斷的輸送帶、將360 deg/拆成多個工位的旋轉盤。
兩者選用的差異就在無限循環。因為絕對型編碼器是一定有範圍限制的,且範圍越大的,價格也越貴。當絕對型編碼器會溢位時,它的本質就和增量型編碼器一樣了。
所以,以刀庫這個應用來說,其實一般是用增量型編碼器。
增量型編碼器用在任何位置控制上,開電就要homing。所以雖然我們是用絕對型編碼器,但因為我們的工況其實是增量型的工作,所以建議**開機homing**。
> 週期性工作的有週期,但是單位不同,e.g. 鏈狀刀庫可能是800cm ,轉盤則是360 deg
## 其它解法
如果就是希望不做homing ,並且有絕對型編碼器了話,能不能不做homing。
### 編碼器支援
是否能達成取決於幾個條件
1. 刀庫cycle < encoder overflow value,否則同一個值,對應n個可能的刀庫位置。(1-multi isn't fulfill function definition)
2. 同上面猜測問題點 的尾部,編碼器的溢位值 是 刀庫cycle的倍數,由於刀庫cycle是機械無法改變。只能動編碼器的溢位值。
1. 由於驅動器斷電時永遠不知道實際的機器發生什麼,所以一但上電就要 **無條件相信** 編碼器的值,所以修改encoder 溢位值的工作一定影響在編碼器上。
1. 如果編碼器可以設定溢位值,可以完美達成。
2. 如果編碼器可以設定位置值,不能設定溢位值,則若在驅動器斷電情況下overflow, underflow,仍會出錯。除非能保證不溢位。
* e.g. tamagawa t-format 用rs485, 要有電池才能工作。
3. 絕對型編碼器也不一定能調。
1. 如果絕對型編碼器的做法是純機械式的。就一定無法調整
1. 有部份電子式的理論上可以調整,但重裝電池後就非要homing 不可。e.g. tamagawa
#### 部份支援
編碼器支援是很困難的,驅動器的程式才可控。cia402 有 607C home offset。如果在overflow的瞬間,將跳變的差值算出並修改此值。效果同 第 編碼器支援-2-1-2 點。斷電不溢位了話可行。 但是cia402 有建議,只在homing mode 修改607C。
> NOTE The activation of a new value of the object home offset is manufacturer-specific. It is
recommended to apply the new value only while the drive is in homing mode.
### 增加規範
cia402 本身對encoder 的類型沒有做很多的規範,特別是大部份都假設是增量型而非絕對型的。
> * 607Ch: Home offset
> 對abs encoder來說,一般的流程就是在裝機後,因為不確定encoder的位置(第幾圈),先用一般的homing 模式+sensor 設定儲存607C的值。下次開機以後都不再需要homing 的流程。直接用此607C值和encoder的讀值相加就知道目前座標。
驅動器無法記憶 abs encoder overflow的原因在於,它要無條件相信abs encoder 的input value。如果驅動器可以做判斷,則可以做一些操作。
如果加上幾個假設/條件,
* 事先知道encoder 的overflow value(encoder 多少bit)
* cia402 無此規範 register
* 最後一次存到ROM裡的絕對位置,和下一次開機間的誤差足夠小。
* 隱含假設斷電後,位置的移動量很小。
* 有不同的做法
* best: 能夠在**斷電時但完全斷電前**,保存最後的絕對位置座標(flash)。
* may work: 週期性的存值(e.g.3s),只要差距夠小就沒事。
* 更好的方法可能是足夠密集的確認,但是只有在與前值有足夠大的差距(足以影響判斷時)才寫入(減少浪費效能,延長flash壽命)。
* 刀庫cycle < encoder overflow value
* 否則會1對多,非function。
如此一來,就能在開機上電時,先把儲存值與abs encoder值相比較,當兩值相差過大時,先將 儲存值/overflow value=y, ans=y\*overflow value +encoder value,if 儲存值~=ans,視為回復成功。
## 結論
~~綜合以上,homing 是最直接有效,保證適用任何的驅動器的方法。~~
~~另外建議要有 zero signal 確保刀庫繞了一圈,我這邊不太確定sandal 有沒有這個功能,不然就是如果旋轉很多次週期後,自動重做 homing動作。~~
我們的目的不是用任意的驅動器都可以兼容。而是只要自己的驅動器,而且我們目標就是要賣整套刀庫,而非單純用刀庫。所以不需考慮相容性問題。
另外梁ㄅㄟ他們真正想用的是5軸上的C軸有絕對型,所以一定要達成。
# 修改
## 52010 ABS_MULTITURN_REV setting.
同理 52007, 52009 都是abs encoder setting.
據說sandal 有這個功能。`52010 ABS_MUTI`。
> 51020 QEP_FPGA_EN
> 絕對值encoder 有BISS 協定。
> EnDat2.2
control.c裡
```c=1786
{{4096}, _DWORD, 52010, STATUSWRITE, 2, 0, 0xFFFFFFFF, NULL, SetEncoderType}, //EncoderRevSet //AUSTON_PARAMETER_ENCODER_ABS_MULTITURN_REV,
```
從 control.c `EncoderRevSet`, 和 `_SetAbsRevolution` 看起來,`ENCODER_ABS_MULTITURN_REV` 並非是直接擴展絕對值編碼器的數值範圍。而是問abs encoder 機械多圈值的上限為何 `u_wAbsMultiReso`(default 12)就4096。同理,`u_wAbsSingleReso`,就是abs encoder 單圈有多少pulse。 `ENCODER_PERIOD_PER_REV` 還不太知道幹麻,看起來也是incremental 才遇到。
另一個出現的是 control.c `MultiDistanceCheck`。
Montion control 則有 `SetEncRotaryRange`, `MultiControl28335`, `CheckPositionRange`。
`AUSTON_PARAMETER_ENCODER_ABS_MULTITURN_REV` ,使用上就call `DBVALUE(ENCODER_ABS_MULTITURN_REV)`
另有 `52023` for `AUSTON_PARAMETER_ENCODER_GET_ABS_MULTITURN_REV`,讀值。但看起來對 ABSOLUTEENCODER 目前無作用。
看起來和 `database.c` `POSITION_MULTICOUNT`有關。就連到`SetMultiRemainder28335` call `SetMultiCnt` call `_SetMultiPos` (`u_AbsMultiPosition = dwPos`)。
### 50064 ENCODERMULTI (not in TMDC yet)
`AUSTON_ACTUALDATA_ENCODERMULTI` implement at `_AbsEncoder_28377.c`
```c=4440
DWORD _GetAbsMulti377()
{
return (u_AbsEncoder.dwLoopCount / u_AbsEncoder.Encoder.wEnPolePairs);
}
```
`wEnPolePairs` 可能是某些encoder 有特別的週期性,其abs loop count 記錄的是換算之前的值。對於大部份的encoder,應該是都沒有用。此值在DB裡是 `52030`, `ENCODER_ENPOLEPAIRS`。此值目前看到都是1。
但只要就是要追 `dwLoopCount`。所以看 `encoderconf.h`, `_AbsEncoder_28377.c` 就對了.
`ReadAbsEncoder`,
`void _InitAbsLoop()`
```c=4393
else if (GetABSType() == ENCODER_TAMAGAWA)
{
u_AbsEncoder.dwLoopCount = u_dwMultiPosition & ((1L << u_wAbsMultiReso) - 1);
if (u_bPositionAdd)
{
if (u_AbsEncoder.dwLoopCount < (1L << (u_wAbsMultiReso - 1)))
u_AbsEncoder.dwLoopCount = u_AbsEncoder.dwLoopCount + (1L<<u_wAbsMultiReso);
}
}
```
`void _SetMultiAbsCom(BOOL bFlag) `其 flag 就是 `POWER_FUNTIONBIT`
```c
if (GetABSType() != ENCODER_HIPERFACE)
_SetMultiAbsCom((DBVALUE(POWER_FUNTIONBIT).dwData & MULTI_ABS)?1:0);
#endif
}
```
```c
{{0}, _DWORD, 51020, STATUSWRITE, 2, 0, 0xFFFFFFFF, NULL, SetFunctionBit}, //AUSTON_PARAMETER_POWER_FUNTIONBIT,
```
這應該是一個register 去決定要不要開各個功能(by different bit)。
### 0x51020 function bit
`MontionControl.c`, `CheckPositionRange()`
可以看出來,`MULTI_ABS`, 可能才是真正的extend abs encoder 功能。
```c=3477
if ((lMinPos > 0 && lMaxPos < 0) || (lMinPos > lTemp && lMaxPos < lTemp))
{
if (!(DBVALUE(POWER_FUNTIONBIT).dwData & MULTI_ABS))
SetDriveError(AUSTONE_POSITION_OVER_RANGE);
}
```
見驅動器datasheet
> P51020 驱动器功能选择
Bit0( CAN_enable) : 通讯使能,通过通讯使能驱动器。
Bit8( ABS_Muti) : 修改绝对位置(360 度转盘禁止使用),
用于防止多圈数位于 0 附近, 仅适用于绝对值编码器和位置
模式, 启用后需要重新归零。
Bit11( POS_TOR) : 位置到位后限制扭矩, 用于较大转盘
机械定位后防止扭矩较大, 而导致的机械上的磨损或者伺服
的报警
Bit13( END_SPEED) : 转盘尾段速度激活
> E00122
位置超过
范围
位置控制中位置范围超过编码器多圈范
围, 启用51018中的bit2可以启用该功能
检查50044编码器数据里面实际编
码器多圈数, 若接近0或4096圈(以
马达实际多圈数为准), 可以分离机
械结构速度模式运行一段时间或激
活51020参数中的ABS_Muti功能,
激活改功能后(sick编码器会自清除)
建议驱动器重启后再次归零
不過目前本來就是有開啟的,沒有開的話,encoder overflow 會 報警。
注意和 `_SetMultiAbsCom` 的關係, `_SetMultiAbsCom((DBVALUE(POWER_FUNTIONBIT).dwData & MULTI_ABS)?1:0);` 就是把`MULTI_ABS` 轉到給encoder 用變為`u_bPositionAdd`。換句話說,可以用這個variable 追multi abs功能。
### 58558 AUSTON_PARAMETER_POSITION_MULTICOUNT
這個值只用在內部的計算,不能設定。應該就是為了事先的 encoder 值處理。總之處理在這裡。
### abs encoder
`_SetMultiAbsCom` 和 `_ReadAbsEncoder` 看起來是用`u_wInitFlag`去dispatch start reading, read success 後就回到 0。
`58514`(`24676`) `POSITION_ACTUAL_VALUE` 是實際位置,也就是最重要的參數。 對應是 MotionControl.c `g_lActLuPosition`
`56008`, `AUSTON_PARAMETER_IDENTIFICATION_ENCODER_ACTUALPOSITION` 是 `當前位置`。 from `Encoder.GetPosition()`。
58514 和 56008 的差異是什麼?
_GetAbsPosition 用到的 `u_AbsMultiPosition` 就在`58558`,一般都是0。
`50064` `ENCODERMULTI`
function bit 打開之後才有開啟。
### save
要做abs 回復一定要有save
看到資料是存在eeprom,找 `Write_EEPROM` 只有 `WORD SaveDB()` 。這是存整個DB,而且只能在motor switch off 時存(blocking function)。
發現有 driver function
`WORD Save_EEPROM(WORD wAddress, int* pnData, WORD wLength)`. database doesn't use this function. directly used in `control.c`, `MotionControl.c`
`void Homeing() ` 有 `Save_EEPROM(DBID(POSITION_MULTICOUNT)*2, (int*)(&DBVALUE(POSITION_MULTICOUNT)), 2);` 除此之外,`Save_EEPROM(DBID(` 開頭的沒有什麼東西。
所以就是原source code 不可能有辦法做斷電回復。這也和經驗相符,不管underflow, overflow,一但發生,因為沒有存actual position 或類似的東西 所以一定會fail。
如果要做了話,我這邊要動的東西有。
1. 在main loop裡週期執行saving. e.g.10s(假設所有控制都在ISR裡執行)。存 POSITION_MULTICOUNT
1. encoder initial 時,和儲存的 POSITION_MULTICOUNT 比較判斷。
# encoder.c
`encoder.h` from `platform.h` from `_AbsEncoder_28377.h` form `encoderconf.h`
`WORD Set_Encoder(ENCODER* pEncoder)` 會bind 1個encoder implement e.g. abs encoder。 然後control.c 會call 這個binding,接下來所有模組要 position value 都用 `DWORD Get_ActPosition()`,包括 MotionControl.c。對於abs encoder,此時此function bind 到 `_AbsEncoder_28377.c`的 `_GetAbsPosition`。
但是有點炸了
讀取動作現在是用 `void EncoderAbsRead()` call `void _SetMultiAbsCom(BOOL bFlag) `。 I think this is because abs encoder require request and response, which different from other encoder.
`AUSTON_PARAMETER_ENCODER_FINERESOLUTION`, `ENCODER_FINERESOLUTION`, `wFineResoBit`.
# sandal 實作解法
* 發現 `u_AbsPosition` 只有32bit,對於39bit encoder(16+23)永遠會有overflow.
* 它實作的方式不是直接用 u_dwPosition 和 u_AbsPosition 換算。
* 而是用 u_AbsEncoder.dwLoopCount 記錄絕對圈數,此圈數用 single turn(lMechAngle)的overflow & underflow 達成,只有initial 時有參考。
* 單圈則是用lMechAngle,所以resolution永遠被壓縮到一定的range。
* 那它如何斷電回復abs encoder 的值?
## scope
一般用CSV 控制時,是讀0x6064的值做回授。所以要做到0x6064可以接收到改動。
0x6064的直實值
u_dwPosiActValue = Get_ActPosition();
最終就是 `Encoder.GetPosition()`
但是我內部如果知道目前的位置超過32bit max 上限了 e.g. 43E
我要怎樣把這個值傳給上位機?如果用0x6064了話。由其是 CSP target position 只能給 ABS value。看來真的要64bit ,最好的方法就是開額外的register。
如果有週期性了話,最好是直接回到原位置就reset ,這樣32bit也一定夠。不過這就是402 protocol 的弱項。而且control loop 如果沒有對應的處理也是白搭,overflow 時。
> 要注意0x6064 , 402 protocal 裡是Integer32。但是sandal 裡是uint32。
目前是說可以做在上位機了。問題一下就解決。
關於encoder 16bit 被 壓縮到12bit。這不會有問題。 e.g. 65535%4096==4095 16bit overflow 時,12bit 也會剛好overflow。從外面看起來,就是abs multi encoder 變成12bit而已。
只要real abs encoder bit >=12bit 就好,如果是8bit就會莫名在255就overflow。此時建議在驅動器端做expand功能。
---
我在另一邊證明type3 用週期性最好,也有描述如何做,就看要不一個 pesudo code。
implement問題要額外考慮在於如果6064 overflow問題,因為此假設功能做在上位機,無法reset 6064,如何處理。其實就是把現在的6064當作encoder value,上位機虛擬一個經過60F2, 607B 設定,會reset的6064。
drive 6064本來就會遇到abs encoder overflow。同樣的方法用在上位機6064 處理就好。e.g. value overflow 時真正的count up value多少就加上而已。結合前面的斷電回復處理斷電overflow。