Initial commit

This commit is contained in:
2026-07-03 16:31:37 +07:00
commit 899c7c637d
1939 changed files with 641750 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
# Luồng gọi từ Action → LiftModule → Động cơ (CiA402 Servo)
## 1. liftCameraByHeight (di chuyển theo chiều cao)
| Bước | Nơi gọi | Gì xảy ra |
|------|---------|------------|
| 1 | **LiftCameraByHeightAction** | Parse HEIGHT (m) → `_liftModule.LiftToPositionAsync(position)` |
| 2 | **LiftModuleService.LiftToPositionAsync** | Kiểm tra Enable, _servo, limit, **State == Ready**. Set `_targetPosition = position`, gọi `_stateMachine.Fire(StartMoving)`. **Log:** `LiftModule: StartMoving fired, target position {Position}` |
| 3 | **State machine** | Chuyển **Ready → Moving**. Trong Moving, `ExecuteOnEntry` chạy `Task.Run(...)`. **Log:** `LiftModule: Moving state entered, calling servo.MoveToPositionAsync(position=...)` |
| 4 | **LiftModuleService (Task.Run)** | `await _servo.MoveToPositionAsync(_targetPosition, ProfileVelocity, ...)`. _servo là **ICiA402Servo** (thực tế là **CiA402Servo** từ DeviceProvider). |
| 5 | **CiA402Servo.MoveToPositionAsync** | **Log:** `CiA402Servo[{DeviceId}]: MoveToPositionAsync position=..., velocity=... -> writing to drive`. Gọi DisableOperation → SetOperationMode(ProfilePosition) → Enable → SetProfileSpeed/Accel/Decel → **SetTargetPositionAsync** (ghi 0x607A) → **StartPositionMoveAsync** (set bit controlword). Tất cả qua **WriteObjectAsync** / **_canOpenDevice** → SDO/PDO → **động cơ**. |
**Kết luận:** Có gọi xuống động cơ. Nếu thấy log `CiA402Servo[...]: MoveToPositionAsync...` thì lệnh đã tới driver và được ghi xuống drive.
---
## 2. homingCamera (homing camera/lift)
| Bước | Nơi gọi | Gì xảy ra |
|------|---------|------------|
| 1 | **HomingCameraAction** | `await _liftModule.HomeAsync(...)` |
| 2 | **LiftModuleService.HomeAsync** | **Log:** `LiftModule: calling servo.StartHomingAsync(method=..., speed=...)`. Gọi _servo.TryFaultResetAsync → EnableAsync → SetHomingMethod/Speed/Offset → **StartHomingAsync**. |
| 3 | **CiA402Servo.StartHomingAsync** | **Log:** `CiA402Servo[{DeviceId}]: StartHomingAsync method=..., speed=... -> writing to drive`. Ghi homing params (0x6098, 0x6099, 0x607C, 0x609A) → SetOperationMode(Homing) → SetControlword(0x000F) → SetControlword(0x001F) start homing. Qua **_canOpenDevice.WriteInt32Async / SetControlwordAsync****động cơ**. |
**Kết luận:** Có gọi xuống động cơ. Nếu thấy log `CiA402Servo[...]: StartHomingAsync...` thì lệnh đã tới driver và được ghi xuống drive.
---
## 3. Điều kiện để liftCameraByHeight thực sự chạy
- **LiftModuleService** phải ở trạng thái **Ready** khi gọi `LiftToPositionAsync`.
Nếu đang Homing / Moving / Error / Uninitialized thì `Fire(StartMoving)` **không đổi state** → không vào Moving → **không gọi _servo.MoveToPositionAsync**.
- **Log cần thấy khi chạy đúng:**
1. `LiftModule: StartMoving fired, target position ...`
2. `LiftModule: Moving state entered, calling servo.MoveToPositionAsync(position=...)`
3. `CiA402Servo[lift-motor]: MoveToPositionAsync position=... -> writing to drive`
Nếu chỉ thấy (1) mà không thấy (2)(3) → state machine không ở Ready khi fire, hoặc _servo null.
---
## 4. Nguồn _servo trong LiftModuleService
- Trong **StartAsync** (IHostedService): `_servo = _deviceProvider.GetDevice(_config.DeviceId)` với **DeviceId** từ config (vd. `Modules:LiftModule:DeviceId` = `"lift-motor"`).
- Device phải là **ICiA402Servo** (thường là **CiA402Servo** PhenikaaX). Nếu không có device hoặc sai type → _servo = null → Moving state log "servo is null" và fire MovingFailed.