0x9C (Read Motor Status 2) 추가 — 모터 동작에 영향 없는 상태 읽기 전용 명령. 실시간 모니터링/데이터 로깅용.0x9D (Read Motor Status 3) 추가 — Control Mode + Phase A/B/C 전류 읽기. Inverse Clarke 변환으로 상전류 계산.or_limit 안전 리미터 추가 — 0xA3 대용량 위치 스텝시 과전류 보호 (REDIRECT / RAMP 두 가지 모드)0xA2 Speed Closed-Loop에 speed_mode 추가 (DATA[1]) — DPS 제어(mode=0, 기존)와 eRPM 제어(mode=1, VESC 내장 PID) 두 가지 속도제어 모드 선택 가능. 기존 DATA[1]=0x00으로 전송하던 코드는 변경 없이 DPS 모드로 동작 (하위 호환).uint64_t 캐스트로 오버플로 방지.comm_can_is_ready() 가드 추가.0xC0 (MIT Control), 0xC1 (Enter Motor Mode), 0xC2 (Exit Motor Mode), 0xC3 (Set Zero Position)τ_out = Kp×(p_des − p_act/GR) + Kd×(v_des − v_act/GR) + τ_ff → iq = τ_out / Kt_out. 출력단 Nm 기준, FOC ISR 내부에서 ~10kHz로 실행.0xA5 Duty 제어. int16 (scale 1/10000, −1.0~1.0). PWM Duty를 직접 설정.0xC4 (Read MIT Params), 0xC5 (Write MIT Params to ROM). V_MAX, T_MAX, Kt, Gear Ratio 파라미터 읽기/쓰기.0xD0 (Read External Sensor). CAN → RS485 → XIAO → MS5803 경로로 온도/압력/기압 읽기.mc_interface_get_motor_dir() 방향 반전 적용. CAN 경계에서만 반전하여 ISR 내부 대칭 구조 유지.0x19 명령 사용.encoder_get_cpr()에서 동적 CPR 반환.0x9B) 명령으로만 해제 가능. 부팅 1.5초 grace period 동안은 과도 fault 자동 클리어. FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET은 latch 대상 제외.CAN_PACKET_FAULT_CLEAR=100), EtherCAT (SDO 0x2030:1에 0 쓰기) 세 경로 모두 지원.DATA[6:7]에 출력단 기준 오프셋 (int16, 0.01 deg/LSB) 전송. offset=0이면 현재위치=0도 (기존 동작), offset=3000이면 현재위치=30도. m_mit_user_zero_set 플래그로 Enter Motor Mode (0xC1) 시 오프셋 보존.| Item | Value |
|---|---|
| CAN ID | 0x140 + Motor_ID |
| Frame Type | Standard (SID) |
| DLC | 8 bytes (fixed) |
| Byte Order | Little-Endian |
MCCONF의 m_invert_direction 설정이 CAN 경계에서 자동 적용된다.
mc_interface_get_motor_dir() 적용.vel_dps (Motor Speed) 필드에 방향 반전 적용.mc_interface_* API를 경유하므로 내부에서 자동 반전됨. MIT의 Kp/Kd 게인은 항상 양수이므로 반전 안함.
공통 응답 포맷 — 0xA1~0xA4, 0x9C, 0xC0 명령에 공통 적용
| Byte | Field | Type | Unit | Note |
|---|---|---|---|---|
DATA[0] | Command ID | uint8 | — | Echo |
DATA[1] | Motor Temperature | int8 | 1 °C / LSB | |
DATA[2-3] | Torque Current (Iq) | int16 | −2048~2048 = −33A~33A | |
DATA[4-5] | Motor Speed | int16 | 1 dps / LSB | |
DATA[6-7] | Encoder Position | uint16 | 14-bit, offset applied | CNT2DEG = 360/16384 |
Command Message for controller (Message ID = 0x140 + Motor ID)
| Description | DATA[0] | DATA[1] | DATA[2] | DATA[3] | DATA[4] | DATA[5] | DATA[6] | DATA[7] |
|---|---|---|---|---|---|---|---|---|
| Read PID data | 0x30 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Write PID to ROM | 0x32 | NULL | Position loop Kp | Position loop Ki | Position loop Kd | |||
| Read encoder data | 0x90 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Write encoder offset | 0x91 | NULL | NULL | NULL | NULL | NULL | Encoder offset | |
| Write current pos as zero | 0x19 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Read multi turns angle | 0x92 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Read Motor Status 2 | 0x9C | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Read Motor Status 3 | 0x9D | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Motor off | 0x80 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Motor stop | 0x81 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Motor running | 0x88 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Torque closed-loop | 0xA1 | NULL | NULL | NULL | Torque current ctrl | Damping Const | ||
| Speed closed-loop | 0xA2 | speed_mode | NULL | NULL | speed control (int32) | |||
| Position closed-loop 1 | 0xA3 | NULL | NULL | NULL | Position control (int32) | |||
| Set Multiturn position | 0xA4 | NULL | Speed limit | Position control (int32) | ||||
| Duty Closed-Loop | 0xA5 | NULL | NULL | NULL | Duty (int16) | NULL | NULL | |
| Read Fault Code | 0xB0 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Clear Error Flag | 0x9B | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Read Max Current | 0xB1 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Write Max Current to ROM | 0xB2 | oc_mode | Motor Curr. Max | Motor Curr. Abs Max | Bat Curr. Max | |||
| MIT Control | 0xC0 | p_des (16bit) | v_hi (8bit) | v_lo4|kp_hi4 | kp_lo (8bit) | Kd (8bit) | τ_ff (8bit) | |
| MIT Enter Motor Mode | 0xC1 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| MIT Exit Motor Mode | 0xC2 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Clear Error Flag | 0x9B | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| MIT Set Zero Position | 0xC3 | NULL | NULL | NULL | NULL | NULL | Offset (int16) | |
| Read MIT Params | 0xC4 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Write MIT Params to ROM | 0xC5 | v_max | t_max | Kt_input (uint16) | GR (uint16) | NULL | ||
| Read External Sensor | 0xD0 | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| Description | DATA[0] | DATA[1] | DATA[2] | DATA[3] | DATA[4] | DATA[5] | DATA[6] | DATA[7] |
|---|---|---|---|---|---|---|---|---|
| Read PID data | 0x30 | 0x00 | Position loop Kp | Position loop Ki | Position loop Kd | |||
| Write PID to ROM | 0x32 | 0x00 | Position loop Kp | Position loop Ki | Position loop Kd | |||
| Read encoder data | 0x90 | Motor_temp | Encoder position | Encoder original | Encoder offset | |||
| Write encoder offset | 0x91 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | Encoder offset | |
| Write current pos as zero | 0x19 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | Encoder offset | |
| Read multi turns angle | 0x92 | Multi-turn Angle (7 bytes LE) | ||||||
| Read Motor Status 2 | 0x9C | Motor_temp | Torque Current | Speed | Encoder Pos | |||
| Read Motor Status 3 | 0x9D | Control Mode | Phase A Curr | Phase B Curr | Phase C Curr | |||
| Motor off | 0x80 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 |
| Motor stop | 0x81 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 |
| Motor running | 0x88 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 |
| Torque closed-loop | 0xA1 | Motor_temp | Torque Current | Speed | Encoder Pos | |||
| Speed closed-loop | 0xA2 | Motor_temp | Torque Current | Speed | Encoder Pos | |||
| Position closed-loop 1 | 0xA3 | Motor_temp | Torque Current | Speed | Encoder Pos | |||
| Set Multiturn position | 0xA4 | Motor_temp | Torque Current | Speed | Encoder Pos | |||
| Duty Closed-Loop | 0xA5 | Motor_temp | Torque Current | Speed | Encoder Pos | |||
| Read Fault Code | 0xB0 | Code1 | Code2 | Code3 | Code4 | Code5 | Code6 | Code7 |
| Read Max Current | 0xB1 | oc_mode | Motor Curr. Max | Motor Curr. Abs Max | Bat Curr. Max | |||
| Write Max Current to ROM | 0xB2 | oc_mode | Motor Curr. Max | Motor Curr. Abs Max | Bat Curr. Max | |||
| Clear Error Flag | 0x9B | Fault Code | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 |
| MIT Control | 0xC0 | Motor_temp | Torque Current | Speed (out dps) | Position (int16, ±12.56rad) | |||
| MIT Enter Motor Mode | 0xC1 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 |
| MIT Exit Motor Mode | 0xC2 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 |
| MIT Set Zero Position | 0xC3 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | Offset echo | |
| Read MIT Params / Write MIT Params | 0xC4 | v_max | t_max | Kt_out (uint16) | GR (uint16) | 0x00 | ||
| Read External Sensor | 0xD0 | valid | Temperature | Pressure | Atmosphere | |||
| ID | Command | Type | Returns Status? |
|---|---|---|---|
0x30 | Read PID Data | Read | No (PID gains) |
0x32 | Write PID to ROM | Write | No (echo) |
0x90 | Read Encoder Data | Read | No (encoder only) |
0x91 | Write Encoder Offset | Write | No (echo) |
0x19 | Write Current Pos as Zero | Write | No (offset) |
0x92 | Read Multi-Turn Angle | Read | No (angle only) |
0x9C | Read Motor Status 2 | Read | Yes |
0x9D | Read Motor Status 3 | Read | Yes (phase currents) |
0x80 | Motor Off | Control | No (ACK) |
0x81 | Motor Stop | Control | No (ACK) |
0x88 | Motor Running (Start) | Control | No (ACK) |
0xA1 | Torque Closed-Loop | Control | Yes |
0xA2 | Speed Closed-Loop | Control | Yes |
0xA3 | Position Closed-Loop 1 | Control | Yes |
0xA4 | Set Multiturn Position | Control | Yes |
0xA5 | Duty Closed-Loop | Control | Yes |
0xB0 | Read Fault Code | Read | No (fault codes) |
0xB1 | Read Max Current | Read | No (current limits) |
0xB2 | Write Max Current to ROM | Write | No (echo) |
0xC0 | MIT Control | Control | Yes |
0xC1 | MIT Enter Motor Mode | Control | No (ACK) |
0xC2 | MIT Exit Motor Mode | Control | No (ACK) |
0x9B | Clear Error Flag | Write | No (fault_code after clear) |
0xC3 | MIT Set Zero Position | Write | No (ACK + offset echo) |
0xC4 | Read MIT Params | Read | No (MIT params) |
0xC5 | Write MIT Params to ROM | Write | No (echo as 0xC4) |
0xD0 | Read External Sensor | Read | No (sensor data) |
Read position PID gains.
RX:
| Byte | Field | Type | Scale |
|---|---|---|---|
DATA[0] | 0x30 | uint8 | — |
DATA[1] | 0x00 | — | — |
DATA[2-3] | Kp | int16 | ×1000 (0.001/LSB) |
DATA[4-5] | Ki | int16 | ×100000 (0.00001/LSB) |
DATA[6-7] | Kd | int16 | ×100000 (0.00001/LSB) |
Write position PID gains to EEPROM (persistent).
RX: Echo of TX
RX:
| Byte | Field | Type | Note |
|---|---|---|---|
DATA[0] | 0x90 | uint8 | — |
DATA[1] | Motor Temp | int8 | 1 °C / LSB |
DATA[2-3] | Encoder Position | uint16 | original − offset |
DATA[4-5] | Encoder Original | uint16 | raw (0–360°) |
DATA[6-7] | Encoder Offset | uint16 |
RX: Echo of TX
RX:
| Byte | Field | Type | Note |
|---|---|---|---|
DATA[0] | 0x92 | uint8 | — |
DATA[1-7] | Motor Angle | int64 (7 bytes LE) | 0.01 deg/LSB, cumulative |
Read-only status query. Returns same motor status format as 0xA1~0xA4 without commanding any motion. Safe for continuous polling.
RX: Standard Motor Status Response format
| Byte | Field | Type | Unit | Note |
|---|---|---|---|---|
DATA[0] | 0x9C | uint8 | — | Echo |
DATA[1] | Motor Temperature | int8 | 1 °C / LSB | |
DATA[2-3] | Torque Current (Iq) | int16 | −2048~2048 = −33A~33A | |
DATA[4-5] | Motor Speed | int16 | 1 dps / LSB | |
DATA[6-7] | Encoder Position | uint16 | 14-bit, offset applied | CNT2DEG = 360/16384 |
Read-only status query returning control mode and phase currents (A/B/C).
Based on RMD protocol 0x9D with control_mode added in DATA[1] (originally NULL).
RX:
| Byte | Field | Type | Unit | Note |
|---|---|---|---|---|
DATA[0] | 0x9D | uint8 | — | Echo |
DATA[1] | Control Mode | uint8 | enum | See table below |
DATA[2-3] | Phase A Current | int16 | 1A / 64 LSB | iA = i_alpha |
DATA[4-5] | Phase B Current | int16 | 1A / 64 LSB | iB = −0.5·i_alpha + √3/2·i_beta |
DATA[6-7] | Phase C Current | int16 | 1A / 64 LSB | iC = −(iA + iB) |
Control Mode Values:
| Value | Mode | CAN Command Origin |
|---|---|---|
| 0 | NONE_CONTROL | Initial state |
| 1 | MOTOR_RELEASE | 0x80 Motor Off |
| 2 | CURRENT_BRAKE | Current brake |
| 3 | DUTY_CONTROL | 0x88 Motor Start |
| 4 | CURRENT_CONTROL | 0xA1 Torque |
| 5 | DAMPED_CURRENT_CONTROL | 0xA1 w/ damping_kd |
| 7 | POSITION_CONTROL_ACCUM | 0xA3 Direct PID |
| 8 | DPS_CONTROL_TIMEOUT | Speed timeout |
| 9 | DPS_CONTROL_DURATION | 0xA2 Speed (mode=0) / 0x81 Stop |
| 10 | SERVO_CONTROL | 0xA4 / or_limit redirect |
| 11 | TRAJ_CONTROL | Trajectory |
| 12 | MIT_CONTROL_MODE | 0xC0 MIT Control |
Turns off motor output, clears operating state and accumulated position.
RX: Echo (all zeros)
Stops motor (speed = 0) but retains operating state. Can be resumed.
RX: Echo (all zeros)
Resume from stop state. Sets duty = 0 (brake mode).
RX: Echo (all zeros)
TX:
| Byte | Field | Type | Note |
|---|---|---|---|
DATA[0] | 0xA1 | uint8 | — |
DATA[1] | 0x00 | — | reserved |
DATA[2-3] | 0x0000 | — | reserved |
DATA[4-5] | iqControl | int16 | −2048~2048 = −33A~33A |
DATA[6-7] | damping_kd | int16 | 0~100 (100 = max damping) |
RX: Motor Status Response Format
Current = (Torque current control value) + (Damping Constant value) × (motor_speed_rps)Supports two speed control modes selectable via DATA[1].
TX:
| Byte | Field | Type | Note |
|---|---|---|---|
DATA[0] | 0xA2 | uint8 | — |
DATA[1] | speed_mode | uint8 | 0 = DPS (default), 1 = eRPM |
DATA[2-3] | 0x0000 | — | reserved |
DATA[4-7] | speedControl | int32 | mode 0: 0.01 dps/LSB, mode 1: 1 eRPM/LSB |
speed_mode values:
| Value | Mode | Control Loop | Unit | Description |
|---|---|---|---|---|
| 0 | DPS | OpenRobot custom | 0.01 dps/LSB | 위치제어 기반 사다리꼴 프로파일 속도제어 (기본값) |
| 1 | eRPM | VESC built-in PID | 1 eRPM/LSB | VESC 내장 PID 속도제어 루프 (mc_interface_set_pid_speed) |
RX: Motor Status Response Format (동일)
Direct position PID control. No velocity limiting — large steps cause full current output immediately.
TX:
| Byte | Field | Type | Note |
|---|---|---|---|
DATA[0] | 0xA3 | uint8 | — |
DATA[1-3] | 0x000000 | — | reserved |
DATA[4-7] | angleControl | int32 | 0.01 deg / LSB |
RX: Motor Status Response Format
or_limit safety limiter or prefer 0xA4 for large moves.
Position control with velocity limiting via servo controller. Recommended for large position moves.
TX:
| Byte | Field | Type | Note |
|---|---|---|---|
DATA[0] | 0xA4 | uint8 | — |
DATA[1] | 0x00 | — | reserved |
DATA[2-3] | maxSpeed | uint16 | 1 dps / LSB (1~25000) |
DATA[4-7] | angleControl | int32 | 0.01 deg / LSB |
RX: Motor Status Response Format
RX:
| Byte | Field | Note |
|---|---|---|
DATA[0] | 0xB0 | — |
DATA[1-7] | Fault codes 1~7 | Oldest to newest |
Fault Code Table (10진수값):
| Code | Fault | Code | Fault |
|---|---|---|---|
| 0 | NONE | 14 | FLASH_CORRUPTION |
| 1 | OVER_VOLTAGE | 15 | HIGH_OFFSET_CURRENT_SENSOR_1 |
| 2 | UNDER_VOLTAGE | 16 | HIGH_OFFSET_CURRENT_SENSOR_2 |
| 3 | DRV | 17 | HIGH_OFFSET_CURRENT_SENSOR_3 |
| 4 | ABS_OVER_CURRENT | 18 | UNBALANCED_CURRENTS |
| 5 | OVER_TEMP_FET | 19 | BRK |
| 6 | OVER_TEMP_MOTOR | 20 | RESOLVER_LOT |
| 7 | GATE_DRIVER_OVER_VOLTAGE | 21 | RESOLVER_DOS |
| 8 | GATE_DRIVER_UNDER_VOLTAGE | 22 | RESOLVER_LOS |
| 9 | MCU_UNDER_VOLTAGE | 23 | FLASH_CORRUPTION_APP_CFG |
| 10 | BOOTING_FROM_WATCHDOG_RESET | 24 | FLASH_CORRUPTION_MC_CFG |
| 11 | ENCODER_SPI | 25 | ENCODER_NO_MAGNET |
| 12 | ENCODER_SINCOS_BELOW_MIN_AMPLITUDE | 26 | ENCODER_MAGNET_TOO_STRONG |
| 13 | ENCODER_SINCOS_ABOVE_MAX_AMPLITUDE |
RX:
| Byte | Field | Type | Note |
|---|---|---|---|
DATA[0] | 0xB1 | uint8 | — |
DATA[1] | OC_Mode | uint8 | 0=LIMIT, 1=LATCH, 2=REPORT, 3=DISABLED |
DATA[2-3] | Motor Current Max | int16 | 0.01 A / LSB |
DATA[4-5] | Motor Current Abs Max | int16 | 0.01 A / LSB |
DATA[6-7] | Battery Current Max | int16 | 0.01 A / LSB |
DRV8301_OC_LIMIT = 0, DRV8301_OC_LATCH_SHUTDOWN = 1, DRV8301_OC_REPORT_ONLY = 2, DRV8301_OC_DISABLED = 3Same format as 0xB1 RX (with 0xB2 as DATA[0]).
TX:
| Byte | Field | Type | Note |
|---|---|---|---|
DATA[0] | 0xB2 | uint8 | — |
DATA[1] | OC_Mode | uint8 | 기본값 3 (DISABLED) 권장 |
DATA[2-3] | Motor Current Max | int16 | 0.01 A/LSB (예: 2000 = 20A) |
DATA[4-5] | Motor Current Abs Max | int16 | 0.01 A/LSB (예: 15000 = 150A) |
DATA[6-7] | Battery Current Max | int16 | 0.01 A/LSB (예: 9900 = 99A) |
RX: Echo of TX
DRV8301_OC_LIMIT = 0, DRV8301_OC_LATCH_SHUTDOWN = 1, DRV8301_OC_REPORT_ONLY = 2, DRV8301_OC_DISABLED = 3PWM Duty를 직접 설정. −1.0 ~ 1.0 범위의 Duty를 int16 (scale ×10000)으로 전송.
| Byte | Field | Type | Note |
|---|---|---|---|
DATA[0] | 0xA5 | uint8 | Command |
DATA[1-3] | Reserved | - | 0x00 |
DATA[4-5] | Duty | int16 LE | −10000 ~ 10000 (= −1.0 ~ 1.0) |
DATA[6-7] | Reserved | - | 0x00 |
RX: Motor Status Response (공통 포맷 — temp, torque current, speed, encoder pos)
or_limit — Position Command Safety LimiterFirmware-level protection against dangerous large position jumps via 0xA3.
Without protection, a large position step causes the PID to output maximum current instantaneously, which can trigger DRV/FET overcurrent faults.
| 0xA3 — Direct PID | 0xA4 — Servo Controller | |
|---|---|---|
| Control Loop | run_pid_control_pos_accum() @10kHzoutput = Kp·e + Ki·∫e + Kd·de/dt → iq = output × I_max |
Trapezoidal velocity profile generator Speed capped at Vel_maximum (DPS) |
| Velocity Limit | None — full current immediately | Yes — maxSpeed parameter |
| Characteristics | Fast response, best for small steps & tracking | Smooth accel/decel, safe for large moves |
Intercept point: app_openrobot_set_position() (command reception) + control loop (auto-return)
When |target − current_pos| > max_step:
|target − current_pos| ≤ max_step, automatically switches back to Direct PID.This means both single-shot and repeated 0xA3 commands always end up in Direct PID at steady state:
| Parameter | Description | Default |
|---|---|---|
deg | Step threshold — redirect if |delta| exceeds this. Also used as auto-return threshold. | 60° |
dps | Max speed for servo controller redirect path | 10000 dps |
Intercept point: run_pid_control_pos_accum() (inside Direct PID loop @10kHz)
The position controller remains 0xA3 Direct PID, but the PID output increase rate is clamped:
| Parameter | Description | Default |
|---|---|---|
ramp_ms | Time for PID output to ramp from 0 to 100% | 5 ms |
| Mode 1 (REDIRECT) | Mode 2 (RAMP) | |
|---|---|---|
| Intercept point | Command reception + control loop | Direct PID loop (10kHz) |
| Method | Switches to servo controller | Limits PID output slew rate |
| Position controller | Servo → auto-return to Direct PID | Always Direct PID |
| Steady state | Direct PID (auto-return) | Direct PID |
| Velocity profile | Trapezoidal (accel→cruise→decel) | None (PID response with ramp) |
| Current limiting | Indirect (via velocity limit) | Direct (output rate limit) |
| Default params | 60° threshold, 10000 dps | 5 ms (0→full) |
| Advantage | Smooth profile, intuitive | Simple, preserves PID characteristics |
or_limit).
CubeMars AK 시리즈 호환 임피던스 제어 프로토콜. 로봇 관절의 컴플라이언트 제어에 사용되며, 매 제어 사이클마다 위치/속도 목표값과 강성/감쇠 게인 및 피드포워드 토크를 전송한다. 모든 파라미터는 출력단(output-side) Nm 기준으로 동작하며, 기어비(GR)와 토크 상수(Kt_out)를 통해 모터단 전류(Iq)로 자동 변환된다.
MIT 임피던스 제어는 FOC ISR 내부에서 ~10kHz 주기로 실행된다. 출력단 토크(τ_out, Nm)를 계산한 후 Kt_out으로 나누어 전류(Iq) 지령으로 변환한다. FOC 전류 루프의 Iq 기준값으로 작용하므로, 외부 PID를 거치지 않고 최소 지연으로 토크를 생성한다.
flux_linkage와 pole_pairs에서 자동 계산 (Kt = 1.5 × (p/2) × flux).0xC4 Read / 0xC5 Write to ROM으로 설정 변경. 부팅 시 EEPROM에서 자동 로드.
| 변수 | 단위 | 범위 | 역할 |
|---|---|---|---|
| p_des | rad | ±12.5 | 목표 위치 (출력단). 엔코더 multiturn 누적 각도를 GR로 나눈 출력단 좌표계 기준. 0xC3 Set Zero 후 0.0이 현재 위치가 된다. m_invert_direction 설정 시 CAN 경계에서 부호 반전. |
| v_des | rad/s | ±V_MAX | 목표 속도 (출력단). 정지 유지 시 0, 궤적 추종 시 원하는 속도 프로파일 값. Kd와 함께 댐핑 제어에 사용. V_MAX는 EEPROM 설정값 (기본 45 rad/s, 0xC4/0xC5로 변경 가능). |
| Kp | Nm/rad | 0–500 | 위치 강성 (스프링 상수). 출력단 위치 오차 1 rad당 발생시킬 토크(Nm). 값이 클수록 단단하게 위치를 유지하고, 0이면 위치 피드백 없음. 로봇 관절의 가상 스프링 역할. 예: Kp=10이면 1 rad 오차 시 10 Nm의 복원 토크 발생. |
| Kd | Nm·s/rad | 0–5 | 속도 감쇠 (댐퍼 상수). 출력단 속도 오차 1 rad/s당 발생시킬 토크(Nm). Kp와 함께 사용하면 진동을 억제하고, 단독(Kp=0)으로 사용하면 점성 마찰처럼 동작. 예: Kd=0.5이면 1 rad/s 속도 오차 시 0.5 Nm의 감쇠 토크 발생. |
| τ_ff | Nm | ±T_MAX | 피드포워드 토크. 임피던스 제어와 무관하게 직접 더해지는 출력단 토크. 중력 보상, 마찰 보상, 또는 역동역학 계산 결과를 주입할 때 사용. Kp=Kd=0이면 순수 토크 제어. T_MAX는 EEPROM 설정값 (기본 33 Nm, 0xC4/0xC5로 변경 가능). m_invert_direction 설정 시 CAN 경계에서 부호 반전. |
댐퍼 항 Kd × (v_des − v_act/GR)에서 v_des는 댐퍼가 허용하는 출력단 기준 속도를 설정한다. 댐퍼는 항상 v_act/GR을 v_des 쪽으로 끌어당긴다.
| v_act/GR | v_des − v_act/GR | Kd 항 | 효과 |
|---|---|---|---|
| 0 (정지) | +5 | +5Kd | 정방향으로 밀어줌 (가속) |
| +3 (느림) | +2 | +2Kd | 더 빠르게 가라고 보조 |
| +5 (정확) | 0 | 0 | 완벽 → 간섭 없음 |
| +8 (빠름) | −3 | −3Kd | 너무 빠르므로 브레이크 |
| v_act/GR | v_des − v_act/GR | Kd 항 | 효과 |
|---|---|---|---|
| 0 (정지) | −5 | −5Kd | 역방향으로 밀어줌 (가속) |
| −3 (느림) | −2 | −2Kd | 더 빠르게 역방향 보조 |
| −5 (정확) | 0 | 0 | 완벽 → 간섭 없음 |
| −8 (빠름) | +3 | +3Kd | 너무 빠르므로 브레이크 |
| v_act/GR | v_des − v_act/GR | Kd 항 | 효과 |
|---|---|---|---|
| +5 (정방향) | −5 | −5Kd | 멈춰! (역방향 전류) |
| −5 (역방향) | +5 | +5Kd | 멈춰! (정방향 전류) |
| 0 (정지) | 0 | 0 | 정지 유지 → 간섭 없음 |
p_des(t)와 함께 v_des(t)를 업데이트하면, 댐퍼가 계획된 운동을 방해하지 않고 외란만 제거하므로 추종 정밀도가 크게 향상된다.
| 사용 패턴 | p_des | v_des | Kp | Kd | τ_ff | 동작 |
|---|---|---|---|---|---|---|
| 순수 토크 제어 | - | - | 0 | 0 | 원하는 토크 | Kp=0, Kd=0이면 τ_ff만 적용. 출력단 Nm 단위의 직접 토크 제어. |
| 위치 유지 (스프링-댐퍼) | 목표 위치 | 0 | >0 | >0 | 0 | 외력에 대해 스프링처럼 복원. Kp↑ = 더 단단, Kd↑ = 진동 감소. |
| 가변 임피던스 | 목표 위치 | 0 | 가변 | 가변 | 0 | 매 사이클 Kp/Kd를 변경하여 충격 시 유연, 정밀 작업 시 강건 전환. |
| 궤적 추종 | 궤적 p(t) | 궤적 v(t) | >0 | >0 | τ(t) | 매 사이클 (p, v, τ)를 업데이트. 로봇 동역학 계산 기반 제어. |
| 중력 보상 | 현재 위치 | 0 | 0 | 0 | 중력 토크 | 관절의 무게를 상쇄하는 출력단 토크(Nm). 사람이 손으로 자유롭게 움직일 수 있음 (제로-G). |
| 점성 감쇠 (백드라이브) | - | 0 | 0 | >0 | 0 | Kp=0이면 위치 구속 없이 속도에 비례하는 저항만 발생. 안전한 물리적 상호작용. |
0xC3 Set Zero Position — 현재 위치를 MIT 영점으로 설정 (런타임 오프셋, EEPROM 비저장). MIT 제어 중에도 전송 가능 — 20ms hold counter가 잔류 CAN 명령을 무시하여 토크 스파이크를 방지한다.0xC1 Enter Motor Mode — 모터 Enable (전류 제어 활성화)0xC0 MIT Control — 주기적 전송 (50~500Hz 권장). 매 프레임마다 5개 파라미터 업데이트.0xC2 Exit Motor Mode — 제어 종료, 모터 Release (전류 0)0xC3)는 런타임 오프셋만 설정하며 EEPROM에 저장하지 않는다. 전원 OFF 시 초기화됨. 엔코더 물리적 영점은 0x19 (Write Current Pos as Zero)를 사용할 것.| 변수 | 소스 | 설명 |
|---|---|---|
| p_act | (mcpwm_foc_get_pos_accum() − offset) × π/180 |
엔코더 multiturn 누적 각도(deg)를 rad으로 변환. MIT Set Zero (0xC3) 오프셋 적용됨. 제어 법칙에서 p_act/GR로 나누어 출력단 좌표로 변환 후 비교. |
| v_act | mcpwm_foc_get_rps() |
FOC에서 계산한 모터단 회전 속도 (rad/s). 제어 법칙에서 v_act/GR로 나누어 출력단 속도로 변환 후 비교. |
0xC3 Set Zero 이후 또는 MIT 모드 최초 진입 시 자동 캡처된 오프셋에서 0으로 시작한다.
GR=1 (직결)이면 p_act/GR = p_act이므로 모터단과 출력단이 동일하다. GR>1이면 모터 여러 바퀴 회전이 출력단 1바퀴에 해당.m_invert_direction 설정 시 p_des, v_des, τ_ff는 CAN 수신 시점에 부호가 반전되고, CAN 응답의 vel_dps도 반전된다.
data8[1]~data8[7]에 56-bit 비트 패킹. CubeMars 표준 인코딩 방식. V_MAX, T_MAX는 0xC4/0xC5로 변경 가능.
| Field | Bits | Range | Resolution | Byte Position |
|---|---|---|---|---|
| p_des (position) | 16 | ±12.5 rad | 0.0004 rad (0.02°) | DATA[1-2] |
| v_des (velocity) | 12 | ±V_MAX rad/s (default 45) | V_MAX/2048 | DATA[3] + DATA[4] hi-nibble |
| Kp (stiffness) | 12 | 0–500 Nm/rad | 0.122 | DATA[4] lo-nibble + DATA[5] |
| Kd (damping) | 8 | 0–5 Nm·s/rad | 0.020 | DATA[6] |
| τ_ff (feedforward) | 8 | ±T_MAX Nm (default 33) | T_MAX/128 | DATA[7] |
MIT 임피던스 제어. 위치/속도/강성/감쇠/피드포워드 토크 5개 파라미터를 7-byte 패킹으로 전송.
RX: Motor Status Response (공통 포맷)
| Byte | Field | Type | Note |
|---|---|---|---|
DATA[0] | 0xC0 | uint8 | Echo |
DATA[1] | Motor Temperature | int8 | 1 °C / LSB |
DATA[2-3] | Torque Current (Iq) | int16 | −2048~2048 = −33A~33A |
DATA[4-5] | Motor Speed | int16 | 1 dps / LSB (출력단: ÷GR 적용, m_invert_direction 반영) |
DATA[6-7] | Encoder Position | uint16 | 14-bit, offset applied |
0xC3 없이도 p_act=0에서 부드럽게 시작한다.
모터 Enable. CubeMars 프로토콜의 Enter Motor Mode (0xFC)에 해당.
모터 Release. CubeMars 프로토콜의 Exit Motor Mode (0xFD)에 해당. 전류를 0으로 만들고 모터를 해제한다.
현재 fault 상태 및 fault 이력(최근 7개)을 모두 클리어한다. Fault Latch 해제 후 모터는 OFF 상태로 복귀.
| Byte | Field | Note |
|---|---|---|
| RX DATA[1] | fault_code | 클리어 후 남은 fault code. 0이면 성공, 0이 아니면 HW fault(DRV) 잔존 |
0x9B를 전송해야 fault가 해제되며, 해제 후 모터는 OFF 상태 (제어 명령을 다시 보내야 동작).FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET (10)은 latch 대상 제외 (항상 자동 클리어).0x2030:1에 0을 쓰면 동일하게 fault clear 동작.CAN_PACKET_FAULT_CLEAR = 100.
MIT 제어의 현재 위치를 영점(또는 지정 오프셋)으로 설정. CubeMars 프로토콜의 Set Zero Position (0xFE)에 해당.
| Byte | Field | Type | Note |
|---|---|---|---|
DATA[6:7] | Offset | int16 LE | 출력단 기준, 0.01 deg/LSB. 0=현재위치가 0도, 3000=현재위치가 30.00도, −4500=현재위치가 −45.00도. 범위: ±327.67° |
m_mit_pos_offset_deg = pos_accum − offset_deg × GR 로 설정. EEPROM에 저장하지 않으므로 전원 OFF 시 초기화된다. 20ms hold counter가 Set Zero 직후 잔류 CAN 명령을 무시하여 토크 스파이크를 방지한다. MIT 제어 중에도 안전하게 전송 가능.0xC3으로 설정한 오프셋은 0xC1 Enter Motor Mode 시 리셋되지 않는다 (m_mit_user_zero_set 플래그). 오프셋을 초기화하려면 offset=0으로 0xC3을 다시 전송.0x19 (Write Current Pos as Zero) 명령을 사용할 것.
MIT 제어 파라미터 (V_MAX, T_MAX, Kt, Gear Ratio) 읽기/쓰기. EEPROM에 영구 저장.
TX (Read):
TX (Write):
| Byte | Field | Type | Note |
|---|---|---|---|
DATA[0] | 0xC5 | uint8 | Command |
DATA[1] | V_MAX | uint8 | Max velocity range (rad/s), default 45 |
DATA[2] | T_MAX | uint8 | Max torque range (A), default 33 |
DATA[3-4] | Kt_input | uint16 LE | ×0.001 Nm/A (motor-side). 0 = auto from MCCONF |
DATA[5-6] | Gear Ratio | uint16 LE | ×0.01 (예: 900 = 9.0) |
DATA[7] | Reserved | - | 0x00 |
RX (공통 — 0xC4 Read 및 0xC5 Write 모두):
| Byte | Field | Type | Note |
|---|---|---|---|
DATA[0] | 0xC4 | uint8 | 항상 0xC4 (Read/Write 모두) |
DATA[1] | V_MAX | uint8 | 현재 V_MAX (rad/s) |
DATA[2] | T_MAX | uint8 | 현재 T_MAX (A) |
DATA[3-4] | Kt_out | uint16 LE | ×0.001 Nm/A (output-side = Kt_input × GR) |
DATA[5-6] | Gear Ratio | uint16 LE | ×0.01 |
DATA[7] | Reserved | - | 0x00 |
Kt_input을 보내고, Read (0xC4) 응답에서는 출력단 Kt_out = Kt_input × GR을 반환한다.
Kt_input=0으로 보내면 MCCONF의 flux_linkage와 pole_pairs에서 자동 계산된다 (Kt = 1.5 × (p/2) × flux).τ_out = Kp × (p_des − p_act/GR) + Kd × (v_des − v_act/GR) + τ_ff → iq = τ_out / Kt_out
외부 센서 데이터 읽기. CAN → RS485 → XIAO RA4M1 → I2C → MS5803 경로로 온도/압력/기압을 읽는다. 응답까지 최대 500ms 소요.
RX:
| Byte | Field | Type | Unit | Note |
|---|---|---|---|---|
DATA[0] | 0xD0 | uint8 | — | Echo |
DATA[1] | Valid | uint8 | 0/1 | 1 = 유효한 데이터 |
DATA[2-3] | Temperature | int16 LE | 0.01 °C / LSB | 예: 2350 = 23.50°C |
DATA[4-5] | Pressure | uint16 LE | 1 mbar / LSB | 예: 1013 = 1013 mbar |
DATA[6-7] | Atmosphere | uint16 LE | 0.0001 atm / LSB | 예: 10000 = 1.0000 atm |
$SNS,temp,pres,atm\n)로 응답한다.| CubeMars 원본 | OpenRobot RMD | 기능 |
|---|---|---|
0xFC (CAN ID) | 0xC1 (DATA[0]) | Enter Motor Mode |
0xFD (CAN ID) | 0xC2 (DATA[0]) | Exit Motor Mode |
0xFE (CAN ID) | 0xC3 (DATA[0]) | Set Zero Position |
| MIT frame (CAN ID) | 0xC0 (DATA[0]) | Impedance Control |
MIT 임피던스 제어가 기존 위치/속도 제어보다 구조적으로 단순하고 직접적인 이유를 비교한다.
| 기존 위치 PID (0xA3 / 0xA4) | MIT Control (0xC0) | |
|---|---|---|
| 제어 구조 | PID (P+I+D) → 정규화 출력 (-1~1) → × lo_current_max | PD + FF → τ_out (Nm) → Iq = τ/Kt_out |
| I-term (적분항) | 있음 (windup 위험) | 없음 (τ_ff로 대체) |
| D-term / 감쇠 | 오차 미분 + LP 필터 | 실제 속도(rad/s) 직접 사용 |
| 출력 단위 | 정규화 비율 (-1~1) | 물리적 토크 (Nm) → 전류 변환 |
| DPS 속도제어 | 프로파일 생성 → 위치 PID (이중 루프) | 단일 루프 |
| 게인 조정 | FW에 고정 (MCCONF) | 매 프레임 전송 (실시간 변경) |
기존 run_pid_control_pos_accum()의 출력 경로:
p_pid_kp의 단위가 “각도오차(deg)당 비율”이므로,
lo_current_max가 바뀌면 같은 Kp에서 실제 전류가 달라진다. 모터/설정마다 게인 재튜닝이 필요하며,
I-term windup 보호도 이 비율 기준이라 미묘한 동적 문제가 발생할 수 있다.
MIT 제어의 출력 경로:
정규화 없이 출력단 토크(Nm)를 직접 계산하므로, Kp=10이면 1 rad 오차에 10 Nm의 토크가 발생한다는 것이 직관적이다. GR과 Kt_out을 통해 자동으로 전류(Iq)로 변환되므로, 모터나 감속기 구성이 바뀌어도 물리적 의미가 유지된다.
기존 PID에는 I-term이 있다. 정지 시 오차가 남으면 I-term이 서서히 누적되다가 한계를 넘으면 한꺼번에 방출되어 오버슈트와 진동을 유발할 수 있다. Anti-windup 보호가 있지만 튜닝이 까다롭다.
MIT 제어에는 I-term이 없다 (순수 PD + FF). 로봇 임피던스 제어에서는 I-term 없이
τ_ff (피드포워드 토크)로 정상상태 오차를 보상하는 것이 표준적이며, windup이 원천적으로 발생하지 않는다.
RMD 0xA2 (DPS) 명령은 dps_control_thread에서 사다리꼴 속도 프로파일(genProfile)을 생성한 뒤,
그 출력(deg_ref)을 다시 위치 PID에 넣는 이중 루프 (프로파일 → 위치 PID → 전류) 구조이다.
두 루프의 게인이 서로 간섭할 수 있으며, 프로파일 생성의 이산화 오차도 누적된다.
MIT는 단일 루프. 임피던스 법칙이 출력단 토크를 계산하고 Kt_out으로 나누어 직접 Iq를 생성하므로 중간 단계가 없다.
CAN Extended ID (EID)를 사용하는 VESC 내장 통신 프로토콜. SID 프로토콜과 별도로 동작하며, MCCONF/APPCONF 파라미터 설정, 펌웨어 업로드, 리부트 등에 사용된다.
| Item | Value |
|---|---|
| Frame Type | Extended (EID, 29-bit) |
| EID Format | (packet_type << 8) | target_id |
| Byte Order | Big-Endian |
| PC Sender ID | 0xFE (254) |
FILL_RX_BUFFER → PROCESS_RX_BUFFER 순서로 데이터를 분할/재조립한다.
| Type | Value | Direction | Description |
|---|---|---|---|
CAN_PACKET_FILL_RX_BUFFER | 5 | TX/RX | Multi-frame 데이터 버퍼 채우기 |
CAN_PACKET_FILL_RX_BUFFER_LONG | 6 | TX/RX | Long index (16-bit offset) 버퍼 채우기 |
CAN_PACKET_PROCESS_RX_BUFFER | 7 | TX/RX | 버퍼 처리 명령 (CRC 포함) |
CAN_PACKET_PROCESS_SHORT_BUFFER | 8 | TX/RX | 짧은 단일 프레임 명령 |
| ID | Command | Type | Description |
|---|---|---|---|
0 | COMM_FW_VERSION | Read | 펌웨어 버전 조회 |
14 | COMM_GET_MCCONF | Read | Motor Configuration 읽기 (~457 bytes) |
13 | COMM_SET_MCCONF | Write | Motor Configuration 쓰기 |
15 | COMM_GET_MCCONF_DEFAULT | Read | Motor Configuration 기본값 읽기 |
17 | COMM_GET_APPCONF | Read | App Configuration 읽기 (~418 bytes) |
16 | COMM_SET_APPCONF | Write | App Configuration 쓰기 |
18 | COMM_GET_APPCONF_DEFAULT | Read | App Configuration 기본값 읽기 |
28 | COMM_REBOOT | Control | MCU 리부트 (IWDG watchdog 리셋) |
31 | COMM_ERASE_NEW_APP | Write | Staging area 삭제 (펌웨어 업로드 1단계) |
32 | COMM_WRITE_NEW_APP_DATA | Write | Staging area에 바이너리 쓰기 (2단계) |
36 | COMM_JUMP_TO_BOOTLOADER | Control | 부트로더로 점프 (3단계) |
46 | COMM_ERASE_BOOTLOADER | Write | 부트로더 섹터 삭제 (부트로더 업로드 시) |
MCCONF 바이너리 페이로드 내 PID 파라미터 오프셋 (MCCONF_SIGNATURE: 0x83C3E1AA). 값은 VESC float32_auto 포맷 (4 bytes Big-Endian).
| Parameter | Speed PID Offset | Position PID Offset |
|---|---|---|
| Kp | 329 | 354 |
| Ki | 333 | 358 |
| Kd | 337 | 362 |
| Kd Filter | 341 | 366 |
| Ramp (eRPM/s) | 350 | — |
COMM_ERASE_NEW_APP(size) — Staging area (Flash sectors 8-10) 삭제COMM_WRITE_NEW_APP_DATA(offset, data) — 바이너리 데이터를 400-byte 청크로 분할 전송COMM_JUMP_TO_BOOTLOADER — 부트로더가 staging → app 영역으로 복사COMM_ERASE_BOOTLOADER — 부트로더 섹터 (Flash sector 11, 128KB) 삭제COMM_JUMP_TO_BOOTLOADER — staging의 부트로더가 sector 11에 자기 자신을 복사| Encoder | Resolution | CPR | Note |
|---|---|---|---|
| AS5047 | 14-bit | 16,384 | CAN SID 프레임과 동일 해상도 |
| MT6835 | 21-bit | 2,097,152 | CAN SID에서는 14-bit로 정규화하여 전송 |
| RLS AksIM-2 | 20-bit | 1,048,576 | BiSS-C 인터페이스. CAN SID에서는 14-bit로 정규화 |
uint64_t 캐스트 사용: (uint64_t)val * ENCODER_CPR_AS5047 / cpr
conf_general_store_eeprom_var_custom() / conf_general_read_eeprom_var_custom()로 접근하는 사용자 정의 EEPROM 변수 목록.
범위: index 0~63. 터미널에서 or_sev [index]로 개별 값 확인 가능.
| Index | Name | Default | Description |
|---|---|---|---|
| 0 | EEP_APP_SELECT | 0 | Application mode (0=VESCular, 1=VESCAT) |
| 1 | EEP_CAN_TERMINAL_RESISTOR_MODE | 0 | CAN terminal resistor (0=OFF, 1=ON) |
| 2 | EEP_VMAX | DPS_VMAX_DEFAULT | DPS control max velocity (dps) |
| 3 | EEP_AMAX | DPS_AMAX_DEFAULT | DPS control max acceleration (dps/s) |
| 4 | EEP_ENC_ZERO_POS | 0 | Encoder zero position offset (deg) |
| 5 | EEP_POS_LIMIT_MODE | 0 | Position limit mode (0=OFF, 1=REDIRECT, 2=RAMP) |
| 6 | EEP_POS_LIMIT_STEP | — | Position limit max step (deg) |
| 7 | EEP_POS_LIMIT_RAMP | — | Position limit ramp rate (/cycle) |
| 8 | EEP_POS_LIMIT_DPS | — | Position limit redirect DPS |
| 9 | EEP_DEMO_MODE | 0 | Demo mode (0=duty, 1=erpm, 2=dps) |
| 10 | EEP_DEMO_VALUE | — | Demo control value |
| 11 | EEP_DEMO_RAMP_TIME | — | Demo ramp time (s) |
| 12 | EEP_DEMO_HOLD_TIME | — | Demo hold time (s) |
| 13 | EEP_DEMO_STOP_TIME | — | Demo stop time (s) |
| 14 | EEP_MIT_V_MAX | 45.0 | MIT max velocity range (rad/s) |
| 15 | EEP_MIT_T_MAX | 33.0 | MIT max torque range (Nm) |
| 16 | EEP_MIT_KT | 0 (auto) | MIT motor-side Kt (Nm/A), 0=auto from flux |
| 17 | EEP_MIT_GR | 9.0 | MIT gear ratio |
| 18 | EEP_PDO_TIMEOUT | 1000 | EtherCAT PDO timeout (ms). v13 |
| 19 | EEP_BIG_ERROR_THRESHOLD | 180.0 | Position big error threshold (output-side deg). v13 |
or_sev [index] — 해당 인덱스의 EEPROM 값 읽기 (u32/i32/float 형태로 출력)or_big — Big Error threshold 현재 값 및 fault 상태 확인or_big [deg] — Big Error threshold 변경 및 EEPROM 저장
| Version | Date | Changes |
|---|---|---|
| v7 | 2024-11-18 | Encoder offset, damping torque, fault code, current limit R/W. |
| v8 | 2025-05-15 | 0xA3 changed to multi-turn direct PID. 0xB0/0xB1/0xB2 added. All control commands changed to single-shot (1회 전달 후 유지). |
| v9 | 2026-02-09 | 0x9C (Read Motor Status 2) added. 0x9D (Read Motor Status 3: control mode + phase currents) added. or_limit safety limiter added. Encoder 14-bit normalization for MT6835. 0xA2 speed_mode (DPS/eRPM) added. |
| v10 | 2026-02-11 | VESC EID Protocol section added. Encoder native resolution (AS5047 14-bit / MT6835 21-bit) with uint64_t overflow fix. COMM_REBOOT HardFault bug fixed. CAN firmware/bootloader upload. Position/Speed PID via MCCONF EID. |
| v11 | 2026-02-23 | MIT Control Protocol added (0xC0~0xC3). CubeMars AK compatible impedance control: position/velocity/Kp/Kd/torque_ff packed in 7 bytes. Enter/Exit Motor Mode and Set Zero Position commands. Control loop architecture, parameter descriptions, usage patterns documented. Duty Closed-Loop (0xA5) added. |
| v12 | 2026-03-05 | MIT Parameter R/W (0xC4/0xC5) added: V_MAX, T_MAX, Kt, GR EEPROM read/write. External Sensor (0xD0) added: MS5803 temperature/pressure via RS485. m_invert_direction support at CAN boundary (all control inputs + vel_dps responses). MIT Set Zero (0xC3) changed to runtime-only offset (no EEPROM, 20ms hold counter). RMD→MIT transition auto-capture offset. RLS AksIM-2 20-bit encoder support added. |
| v13 | 2026-03-18 | EtherCAT Protocol documentation added (PDO/SDO/DC SYNC0/TwinCAT guide). SDO deferred EEPROM store for motor safety. 0x2020 Motor Parameters changed to RW. ESI XML DC-Synchron support. F405 foc_test_capture removed (RAM overflow fix). TwinCAT 3 verified with DC SYNC0. |
OpenRobot MC EtherCAT Slave — SOES 3.1.0 + LAN9252 on STM32F405
| Item | Value |
|---|---|
| ESC Chip | LAN9252 (Microchip), SPI PDI (0x80) |
| MCU | STM32F405RGT6 (168 MHz, Cortex-M4) |
| EtherCAT Stack | SOES 3.1.0 (Simple Open EtherCAT Slave) |
| Mailbox Protocol | CoE (CANopen over EtherCAT) |
| RxPDO Size | 17 bytes (Master → Slave) |
| TxPDO Size | 20 bytes (Slave → Master) |
| DC SYNC0 | Supported (AssignActivate = 0x0300) |
| Supported Masters | TwinCAT 3, pysoem (Python) |
PDO Index: 0x1600, Object Index: 0x7000, SM2, 17 bytes total
| Byte | Field | Type | Scale | Range (raw) | Range (real) | Description |
|---|---|---|---|---|---|---|
| 0 | control_mode | uint8 | — | 0x80–0xC0 | — | Command code (see Control Mode table) |
| 1–4 | target_position | int32 | ×10000 | ±2,147,483,647 | ±214,748 deg / ±214,748 rad | Position target. 0xA3/0xA4: deg, 0xC0(MIT): rad |
| 5–8 | target_velocity | int32 | ×10000 | ±2,147,483,647 | 0xA2: unlimited dps / 0xA4: 0~25,000 dps / 0xC0: rad/s (±V_MAX) | Velocity target or speed limit |
| 9–12 | target_torque | int32 | ×10000 | ±2,147,483,647 | 0xA1: ±200 A (clamp) / 0xA5: ±1.0 duty (clamp) / 0xC0: ±T_MAX Nm | Current, duty, or torque depending on mode |
| 13–14 | kp | uint16 | ×100 | 0–65535 | 0xA1: 0~100 (damping) / 0xC0: 0~500 Nm/rad (MIT Kp) | Stiffness or damping coefficient |
| 15–16 | kd | uint16 | ×1000 | 0–65535 | 0xC0: 0~5 Nm·s/rad (MIT Kd) | Damping — MIT mode only |
l_current_max (기본 60A, HW 상한 ±64A)에서 먼저 제한됨.PDO Index: 0x1A00, Object Index: 0x6000, SM3, 20 bytes total
| Byte | Field | Type | Scale | Range (real) | Description |
|---|---|---|---|---|---|
| 0 | control_mode | uint8 | — | 0x80–0xC0 | Active control mode echo (same codes as RxPDO) |
| 1 | fault_code | uint8 | — | 0–26 | mc_fault_code: 0=OK, 1=OV, 2=UV, 3=DRV, 4=OC, 5=FET_OT, 6=MOT_OT, 11=ENC_SPI, 25=NO_MAG, 26=BIG_ERR |
| 2–5 | actual_position | int32 | ×10000 | multi-turn deg (MIT: output-side deg ÷GR) | Accumulated position. MIT 모드에서는 (pos − enc_offset − mit_offset) / GR |
| 6–9 | actual_velocity | int32 | ×10000 | dps (degrees per second) | Angular velocity from FOC observer |
| 10–13 | actual_torque | int32 | ×10000 | A (filtered Iq current) | Directional torque current, filtered |
| 14–15 | bus_voltage | uint16 | ×100 | 0~70.0 V (HW dependent) | DC bus input voltage |
| 16 | temp_motor | int8 | — | −128~127 °C | Motor temperature (NTC sensor) |
| 17 | temp_mosfet | int8 | — | −128~127 °C | MOSFET temperature (DRV8301 internal) |
| 18–19 | encoder_pos | uint16 | — | 0–16383 (14-bit) | Raw encoder count. 21-bit 엔코더는 >>7 정규화 |
Same command codes as CAN RMD protocol. Set via RxPDO control_mode byte.
| Code | Name | Used RxPDO Fields | Description |
|---|---|---|---|
0x80 | MOTOR_OFF | — | Release motor, clear faults. Always start with this. |
0x81 | MOTOR_STOP | — | Active stop (DPS = 0, holds position) |
0x88 | MOTOR_START | — | Standby (duty = 0) |
0xA1 | TORQUE_CLOSED_LOOP | target_torque (A), kp (damping) | Current/torque control. kp>0 enables damping. |
0xA2 | SPEED_CLOSED_LOOP | target_velocity (dps) | Speed control via DPS controller |
0xA3 | POSITION_CLOSED_LOOP_1 | target_position (deg) | Direct PID position control (multi-turn, no speed limit). Big Error protection enabled. |
0xA4 | SET_MULTITURN_POSITION | target_position (deg), target_velocity (dps) | Position + speed limit servo control |
0xA5 | DUTY_CLOSED_LOOP | target_torque (duty, -1~+1) | Direct PWM duty control |
0xC0 | MIT_CONTROL | All 5 fields | 5-param impedance control (rad units). τ = Kp×(p_des−p_act) + Kd×(v_des−v_act) + τ_ff |
| Item | Value |
|---|---|
| Default | 180° (출력단 기준) |
| SDO | 0x2030:8 (RW, EEPROM-backed) |
| Terminal | or_big (읽기) / or_big [deg] (쓰기+EEPROM 저장) |
| EEPROM Index | 19 (EEP_BIG_ERROR_THRESHOLD) |
| 기준 | 출력단 deg — 0xA3, 0xC0 모두 동일 기준 |
| Fault Clear | PDO 0x80 (MOTOR_OFF) 전송 시에만 클리어 (latched) |
| Mode | 입력 단위 | FW 내부 변환 | 발동 조건 |
|---|---|---|---|
0xA3 Position | 모터단 deg | pos_err ÷ GR | 모터단 |cmd−actual| > 1620° (= 180° × 9, 모터 4.5회전) |
0xC0 MIT | 출력단 rad | 이미 출력단 | 출력단 |cmd−actual| > 3.14 rad (= π, 출력 반회전) |
0xA4 Multiturn | 모터단 deg | — | Big Error 미적용 (speed limit으로 보호) |
pos_err / GR > threshold)pos_err_output_deg > threshold)49 objects in 12 groups (0x2000–0x2090). Accessible via CoE SDO protocol (TwinCAT CoE-Online, pysoem sdo_read/sdo_write).
| Sub | Name | Type | Access | Description |
|---|---|---|---|---|
| 1 | Current_Kp | REAL32 | RW | FOC current loop proportional gain |
| 2 | Current_Ki | REAL32 | RW | FOC current loop integral gain |
| Sub | Name | Type | Access | Description |
|---|---|---|---|---|
| 1 | Speed_Kp | REAL32 | RW | Speed proportional gain |
| 2 | Speed_Ki | REAL32 | RW | Speed integral gain |
| 3 | Speed_Kd | REAL32 | RW | Speed derivative gain |
| 4 | Speed_Kd_filter | REAL32 | RW | Speed Kd low-pass filter coefficient |
| 5 | Speed_min_erpm | REAL32 | RW | Minimum eRPM for speed control |
| Sub | Name | Type | Access | Description |
|---|---|---|---|---|
| 1 | Pos_Kp | REAL32 | RW | Position proportional gain |
| 2 | Pos_Ki | REAL32 | RW | Position integral gain |
| 3 | Pos_Kd | REAL32 | RW | Position derivative gain |
| 4 | Pos_Kd_filter | REAL32 | RW | Position Kd low-pass filter coefficient |
| Sub | Name | Type | Access | Description |
|---|---|---|---|---|
| 1 | Enc_offset | REAL32 | RW | Encoder offset (degrees) |
| 2 | Encoder_CPR | UINT32 | RO | Counts per revolution (AS5047: 16384, MT6835: 2097152) |
| Sub | Name | Type | Access | Description |
|---|---|---|---|---|
| 1 | Max_current | REAL32 | RW | Motor max current limit (A). Also sets l_current_min = −value. Clamped by HW_LIM_CURRENT (±64A). |
| 2 | Abs_max_current | REAL32 | RW | Absolute max current (A). Direction-independent protection limit. |
| 3 | Torque_constant | REAL32 | RW | Motor-side Kt (Nm/A). Write updates MIT Kt parameter. Read returns Kt_out (= Kt × GR). |
| 4 | Motor_poles | UINT8 | RW | Number of motor pole pairs |
| 5 | Flux_linkage | REAL32 | RW | PM flux linkage (Wb). Used for Kt auto-calculation: Kt = 1.5 × (P/2) × flux |
| Sub | Name | Type | Access | Description |
|---|---|---|---|---|
| 1 | Fault_code | UINT8 | RO | 0=OK, 1=OV, 2=UV, 3=DRV, 4=OC, 5=FET_OT, 6=MOT_OT, 11=ENC_SPI, 25=NO_MAG, 26=BIG_ERR |
| 2 | PDO_timeout_flag | UINT8 | RO | 1 = PDO timeout detected, auto-clears on PDO resume |
| 3 | VIN_voltage | REAL32 | RO | Input voltage (V) |
| 4 | Temp_MOSFET | REAL32 | RO | MOSFET temperature (°C) |
| 5 | Temp_limit_FET | REAL32 | RW | FET over-temperature threshold (°C) |
| 6 | Temp_limit_motor | REAL32 | RW | Motor over-temperature threshold (°C) |
| 7 | PDO_timeout_ms | UINT32 | RW | PDO timeout period (ms). Default: 1000. EEPROM-backed. |
| 8 | Big_error_threshold | REAL32 | RW | Position big error threshold (output-side deg). Default: 180. EEPROM-backed. |
| Sub | Name | Type | Access | Description |
|---|---|---|---|---|
| 1 | Position_deg | REAL32 | RO | Multi-turn accumulated position (degrees) |
| 2 | Velocity_dps | REAL32 | RO | Angular velocity (degrees per second) |
| 3 | Torque_current | REAL32 | RO | Iq torque current (A) |
| 4 | Control_mode | UINT8 | RO | Active control mode code |
| Sub | Name | Type | Access | Description |
|---|---|---|---|---|
| 1 | MIT_V_max | REAL32 | RW | Max velocity range (rad/s). Default: 45.0. EEPROM-backed. |
| 2 | MIT_T_max | REAL32 | RW | Max torque range (Nm). Default: 33.0. EEPROM-backed. |
| 3 | MIT_Kt_motor | REAL32 | RW | Motor-side Kt (Nm/A). 0 = auto from flux. EEPROM-backed. |
| 4 | MIT_Gear_ratio | REAL32 | RW | Gear ratio. Default: 9.0. EEPROM-backed. |
| 5 | MIT_Set_zero | UINT8 | RW | Write 1 to set zero position (runtime offset, auto-clears) |
| Sub | Name | Type | Access | Description |
|---|---|---|---|---|
| 1 | DPS_Vmax | REAL32 | RW | Maximum velocity for DPS/servo control (dps). EEPROM-backed. |
| 2 | DPS_Amax | REAL32 | RW | Maximum acceleration (dps/s). EEPROM-backed. |
| Sub | Name | Type | Access | Description |
|---|---|---|---|---|
| 1 | FW_major | UINT8 | RO | Firmware major version |
| 2 | FW_minor | UINT8 | RO | Firmware minor version |
| 3 | HW_name | UINT32 | RO | Hardware name identifier |
| Sub | Name | Type | Access | Description |
|---|---|---|---|---|
| 1 | Pressure_mbar | REAL32 | RO | MS5803 pressure (mbar). Auto-pushed via CAN from XIAO. |
| 2 | Temperature_C | REAL32 | RO | MS5803 temperature (°C) |
| 3 | Depth_m | REAL32 | RO | Calculated depth (m) |
| Item | Value |
|---|---|
| SYNC0 Supported | Yes (AssignActivate = 0x0300) |
| Default Cycle | 1000 µs (1 kHz, matched to master) |
| SYNC0 Pin | LAN9252 → PD2 (EXTI2 ISR) |
| Free-Run Poll Cycle | ~700 µs (1428 Hz) |
| DC SYNC Poll Cycle | 1000 µs (1000 Hz, synchronized) |
or_soes 터미널 명령으로 DC SYNC0 상태 (ACTIVE/OFF, cycle, pulses, mode) 확인 가능합니다.
pysoem (Motor Tool) vs TwinCAT 3 — 동일 슬레이브(LAN9252 + F405)에서 측정한 실제 성능
| 항목 | pysoem (Motor Tool) | TwinCAT 3 |
|---|---|---|
| PDO 주기 | 2 ms (500 Hz) | 1 ms (1 kHz), 최소 100 µs 가능 |
| FW Poll cycle | 700 µs (FREE-RUN) | 1000 µs (DC SYNC 동기) |
| 지터 (Jitter) | 수백 µs ~ 15 ms (Windows 스레드 스케줄러 의존) | < 1 µs (커널 레벨 RT 스케줄러) |
| DC SYNC0 | 소프트웨어 동기 (불안정) | 하드웨어 동기 (안정) |
| 동기화 모드 | FREE-RUN | SYNC (DC-Synchron) |
| 실시간성 | 비실시간 (Windows userspace) | 하드 리얼타임 (RT 커널, CPU 코어 전용) |
| 최악 PDO 지연 | ~20 ms (Windows 스케줄러 최악) | < 10 µs |
| PDO timeout 위험 | 있음 (지터로 인한 누락 가능) | 거의 없음 |
| 권장 용도 | 파라미터 설정, 모니터링, 간단한 테스트 | 정밀 모션 제어, 로봇 운용 |
time.sleep()으로 주기를 유지하므로 Windows 스레드 스케줄러에 의존합니다. 최악의 경우 PDO 한 주기가 20ms를 넘어 PDO timeout이 발생할 수 있습니다. 파라미터 설정, SDO 접근, 모니터링 등 비실시간 작업에 적합합니다.C:\TwinCAT\3.1\Config\Io\EtherCAT\ 에 복사__cache\ 폴더 안의 파일 삭제 (캐시 초기화)AT %Q* for outputs, AT %I* for inputs)TwinCAT에서 슬레이브 선택 → CoE-Online 탭에서 SDO Object Dictionary가 자동으로 열거됩니다. 각 object를 더블클릭하여 Read/Write 가능합니다.
PLC에서는 FB_EcCoESdoRead / FB_EcCoESdoWrite 펑션블록으로 런타임 SDO 접근이 가능합니다.
Startup 탭에서 SDO write 명령을 등록하면 부팅 시 자동으로 파라미터를 설정할 수 있습니다.
| Feature | Description |
|---|---|
| PDO Timeout | Configurable timeout (SDO 0x2030:7, default 1000ms). Motor enters FAULT_STOP if no PDO received. Only active when control source = EtherCAT. |
| Big Error Protection | Position error threshold (SDO 0x2030:8, default 180°, output-side). Applies to 0xA3 and 0xC0 modes. Latched fault — requires 0x80 (MOTOR_OFF) to clear. |
| Rate-of-Change Limiting | target_torque and target_velocity changes are rate-limited per PDO cycle to protect against SPI corruption. |
| Control Source Tracking | Automatic tracking of control source (CAN_VESC, CAN_RMD, ECAT, TERMINAL). PDO timeout only triggers for EtherCAT source. |
| Deferred EEPROM Store | SDO writes update RAM immediately but defer flash/EEPROM storage until motor is idle, preventing FOC ISR disruption. |
| Command | Description |
|---|---|
or_soes | Show SOES status: AL state, poll cycle, PDO count, DC SYNC0 state, control mode, errors |
or_s | Quick status: control_mode, ctrl_source, ecat_fault, mc_fault |