# 狀況
> 協助排查,偶爾使用SDO時,會有此狀況,速度設定值會突然降至低速又回至原本速度。
> 不使用SDO 是正常的
工況:
> ethercat SDO發送間隔:100ms
> 會用SDO 輪訊每一條entry。
> 
>
> Speed picture from drive output. Maybe drive save the result in buffer, then output through enthernet.
> 
# 分析
從速度圖可以看到,應該是有某種機制要求drive的command speed(黃色)為接近0。pulse width =1ms,1ms是記錄的週期,而且有些沒有記錄到。可以推測內部的state快速的轉換,才會有時有記錄到,有時沒有。
從actual speed(綠色) 來看,就算沒被記錄到,命令還是有下達的。
由於program 沒有thread和 timeslicing,全部code都是run to complete。從有黃色沒被記錄到的這種特性,表示output data 可能是一個額外的timer ISR,且使用的 data 沒有 buffer。如果計算的時間長或短了一點,剛好output to PC 的 timer ISR內,就會沒看到pulse。
這種情況一般即為權責不清,e.g. 兩個模組可操作同一 global 變數,且兩個模組內部的state也沒有sync。由於在SDO底下發生,有幾種情況。
1. SDO 有control 相關global 變數,並直接控制
* 上述的狀況
3. control 有SDO相關的變數,但是在處理時,沒有處理好。比如SDO有error 要停下,control 在callback裡有停下,但是callback 沒有改變control 自身的state。所以下次routine來就蓋掉了。
4. control or SDO的變數同時被其它module存取,且下達錯誤。
## 事實
透過ethernet定閱的項目,只能是database有的項目。透過這個特性我們知道 `速度設定值(濾波前)` 在database中是id=53000,`u_qSpeedRef` 也是此值的原本存放值(會再做些轉換)
此值直接設定的就在`ecatslv`, `database`。看起來沒有其它的setter funciton。
# code
從 code 裡,有出現SDO字眼的.c檔案有 `CANopenComm`, `coeappl`, `database.c`, `ecatslv.c`, `ethercat.c`, `EthernetPCComm`, `mailbox`, `objdef`, `pressurectrl` ,比較有可能的有 `ecatslv`, `coeappl`, `ethercat`(可能性由可到低)。
在 `ecatslv` 確實有發現 include `control`
其中 `Ecat_DMA()`
```clik=1259
if (DmaMapping.w60FFOffset != 0xFFFF)
{
//lTemp = *((long*)(&u_awPdOutputData[0] + DmaMapping.w60FFOffset));
memcpy(&lTemp, (u_awPdOutputData + DmaMapping.w60FFOffset),sizeof(DWORD)); // odd adress not get right long value
if (u_w402Enable)
lTemp = _IQ(((float)lTemp * 60.0 * Vel402Factor.adwdata[0] / DBVALUE(ENCODER_RESOLUTION).dwData / ENCODER_REV /Vel402Factor.adwdata[1]) / DBVALUE(MOTOR_MAXSPEED).fData);
if (lTemp > _IQ(1.0)) lTemp = _IQ(1.0);
else if (lTemp < _IQ(-1.0)) lTemp = _IQ(-1.0);
if (StatMachine.StopRespFlag == 0)
u_qSpeedRef = _IQmpy(u_qRealVMax, lTemp);
}
if(DmaMapping.w2BB8Offset != 0xFFFF)
{
memcpy(&fTemp, (u_awPdOutputData + DmaMapping.w2BB8Offset),sizeof(DWORD));
lTemp = _IQ(fTemp / DBVALUE(MOTOR_RATEDSPEED).fData);
if(lTemp > u_qRealVMax) lTemp = u_qRealVMax;
else if (lTemp < -u_qRealVMax) lTemp = -u_qRealVMax;
if (StatMachine.StopRespFlag == 0)
u_qSpeedRef = lTemp;
}
```
重點在於有動到 `u_qSpeedRef` 這個`contorl` variable,且是速度ref沒錯,~~但不是0。也有可能是在計算過程出了問題,變為0。~~ speed ref只有很接近0,但不等於0。隨應該要有的speed ref等比縮非常小。
`coeappl.c`, `ethercat.c` 裡都沒有 `u_qSpeedRef`。這一段計算裡出問題最有可能。
但是可以看到,用到了一大堆其它地方的數字,要有當下variable value才能知道是知道發生了什麼
比較大的問題是`ControlMode.wOptionMode != POSITION_MODE` 才會進入這一區,要看drive 是否有主動切換mode,因為user 這端一直維持在position mode。
但是實在沒有其它地方(除control以外)設定 `u_qSpeedRef`,所以我還是認為問題在這。
由於是接近0,我猜可能是分母突然變很大。