Fatigue Test ESP-NOW Unit - Architecture Documentation
Overview
The Fatigue Test ESP-NOW Unit is a unified fatigue testing system that combines motor control, bounds detection, and wireless communication. It supports dual communication interfaces (ESP-NOW and UART) and dual bounds detection methods (StallGuard2 and encoder-based).
System Architecture
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Fatigue Test Unit β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ β
β β ESP-NOW β β FreeRTOS β β Motion β β
β β Receiver ββββββββΆβ Event Queue ββββββββΆβ Controller β β
β β (ISR-safe) β β β β (Point-to-Point)β β
β βββββββββββββββββββ βββββββββββββββββββ ββββββββββ¬βββββββββ β
β β β β
β β βββββββββββββββββββ β β
β β β Global State β β β
β βββββββββββββββββΆβ & Settings βββββββββββββββββββ β
β ββββββββββ¬βββββββββ β
β β β
β ββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββ β
β β β β β
β βΌ βΌ βΌ β
β βββββββββββββββββ βββββββββββββββββ βββββββββββββββββ β
β β UART β β Bounds β β TMC51x0 β β
β β Command β β Finding β β Driver β β
β β Parser β β (Library) β β (SPI) β β
β βββββββββββββββββ βββββββββββββββββ βββββββββ¬ββββββββ β
β β β β
β β β β
β βββββββββΌββββββββ βββββββββΌββββββββ β
β β driver. β β Motor β β
β β homing β β Hardware β β
β β FindBounds β β β β
β βββββββββββββββββ βββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Component Overview
1. ESP-NOW Communication Layer
Files: espnow_protocol.hpp, espnow_receiver.hpp/cpp
- Purpose: Wireless communication with remote controller
- Protocol Version: 1
- Header Size: 6 bytes (sync, version, device_id, type, id, len)
- Max Payload: 200 bytes
- Error Detection: CRC16-CCITT
Features:
- Sync byte validation (0xAA)
- Protocol version checking
- Sequence ID tracking
- CRC16-CCITT checksum
- Queue-based event delivery (ISR-safe)
- MAC address learning (optional pre-configuration)
Key Functions:
1
2
3
4
5
6
EspNowReceiver::init(QueueHandle_t event_queue);
EspNowReceiver::send_config_response(const Settings& s);
EspNowReceiver::send_config_ack(bool ok, uint8_t err_code);
EspNowReceiver::send_status_update(uint32_t cycle, TestState state);
EspNowReceiver::send_error(uint8_t err_code, uint32_t at_cycle);
EspNowReceiver::send_test_complete();
2. UART Command Interface
Location: main.cpp (UartCommandParser)
- Purpose: Direct serial control for debugging and development
- Protocol: Text-based command parser
- Baud Rate: 115200
- Commands:
-f,-d,-b,-c,-a,-s,-h
3. Bounds Detection System
Implementation: TMC51x0 driver library built-in homing subsystem
- Purpose: Detect physical limits of motion and establish coordinate frame
- API:
g_driver->homing.FindBounds(method, options, home_config, cancel_cb)
Supported Methods:
| Method | Description |
|βββ|ββββ-|
| StallGuard | Sensorless stall detection via TMC51x0 StallGuard2 |
| Encoder | Encoder-based bounds detection |
| Switch | Limit switch detection (available in library) |
BoundsOptions Structure (passed to FindBounds):
1
2
3
4
5
6
7
8
9
10
11
12
13
struct BoundsOptions {
float search_speed; // Search velocity (RPM)
float search_span; // Max search distance (degrees)
float backoff_distance; // Backoff from detected bound (degrees)
uint32_t timeout_ms; // Search timeout
float search_accel; // Search acceleration (rev/sΒ²)
float search_decel; // Search deceleration (rev/sΒ²)
float current_reduction_factor; // Current reduction during SG search
StallGuardConfig* stallguard_override; // Optional SG configuration
Unit speed_unit; // Unit for speed values
Unit position_unit; // Unit for position values
Unit accel_unit; // Unit for acceleration values
};
4. Motion Controller
Files: fatigue_motion.hpp, fatigue_motion_impl.hpp
- Purpose: Generate point-to-point back-and-forth motion between bounds
- Features:
- Point-to-point position control (direct VMAX/AMAX)
- Cycle counting (center-crossing detection)
- Configurable dwell time at bounds
- Thread-safe operation (RAII mutex guards)
- Support for both bounded and unbounded operation
Key Methods:
1
2
3
4
5
6
7
8
9
10
void SetFrequency(float freq_hz);
void SetTargetCycles(uint32_t cycles);
void SetDwellTimes(uint32_t min_ms, uint32_t max_ms);
void SetGlobalBounds(float min_deg, float max_deg);
void SetLocalBoundsFromCenterDegrees(float range);
void Start();
void Pause();
void Resume();
void Stop();
FatigueStatus GetStatus() const;
5. Settings Management
Location: espnow_protocol.hpp
Settings are stored in memory and synchronized via ESP-NOW. Extended fields support backward compatibility.
TestUnitSettings Structure:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct TestUnitSettings {
// Base fields (always synchronized)
uint32_t cycle_amount = 1000; // Target cycles
float oscillation_vmax_rpm = 60.0f; // Max velocity during oscillation (RPM)
float oscillation_amax_rev_s2 = 10.0f; // Acceleration during oscillation (rev/sΒ²)
uint32_t dwell_time_ms = 1000; // Dwell time at endpoints (milliseconds)
bool bounds_method_stallguard = true; // Detection method
// Extended fields (0.0f = use TestConfig defaults)
float bounds_search_velocity_rpm = 0.0f; // Search speed (RPM)
float stallguard_min_velocity_rpm = 0.0f; // SG min velocity (RPM)
int8_t stallguard_sgt = 127; // StallGuard threshold [-64..63], 127=default
float stall_detection_current_factor = 0.0f; // Current reduction (0.0-1.0)
float bounds_search_accel_rev_s2 = 0.0f; // Search acceleration (rev/sΒ²)
};
Extended Field Behavior:
- Value of
0.0fβ test unit uses TestConfig defaults - Non-zero value β overrides the default
- Ensures backward compatibility with older remote controllers
Task Architecture
The system uses FreeRTOS tasks for concurrent operation:
| Task | Priority | Stack | Period | Description |
|---|---|---|---|---|
espnow_command_task |
5 | 4KB | Event-driven | Process ESP-NOW commands |
motion_control_task |
5 | 8KB | 10ms | Motor motion updates |
status_update_task |
3 | 4KB | 1000ms | Send status to remote |
uart_command_task |
3 | 4KB | 50ms | Process UART commands |
bounds_finding_task |
4 | 8KB | Dynamic | Created on START, deleted on completion |
Task Communication
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β ESP-NOW ISR ββββββΆβ Raw RX Queue ββββββΆβ espnow_recv_taskβ
βββββββββββββββββββ βββββββββββββββββββ ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββ
β ProtoEvent Queueβ
ββββββββββ¬βββββββββ
β
βββββββββββββββββββββββββββββββββΌβββββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ
βespnow_cmd_task β βbounds_find_task β βmotion_ctrl β
β(commands) β β(on-demand) β βtask β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββ
State Machine
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
βββββββββββββββββββ
β IDLE ββββββββββββββββββββββββββββββββββββ
β (motor off) β β
ββββββββββ¬βββββββββ β
β β
β START command β
βΌ β
βββββββββββββββββββ β
β BOUNDS_FINDING β β
β (task running) β β
ββββββββββ¬βββββββββ β
β β
ββββββββββββββΌβββββββββββββ β
β β β β
βΌ βΌ βΌ β
ββββββββββββββββ ββββββββββββ ββββββββββββ β
β Bounds found β β Cancelledβ β Timeout/ β β
β β β (PAUSE) β β Error β β
ββββββββ¬ββββββββ ββββββ¬ββββββ ββββββ¬ββββββ β
β β β β
β β ββββββββββββββββββββββββββββββ€
β β β
βΌ βΌ β
βββββββββββββββββββ βββββββββββββββββββ β
β RUNNING β β PAUSED β β
β(point-to-point) ββββΆβ (motor off) βββββββββββββββββββββββββββββ€
ββββββββββ¬βββββββββ βββββββββββββββββββ STOP β
β β² β
β PAUSE β RESUME β
ββββββββββββββββββββββ β
β β
β Target cycles reached β
βΌ β
βββββββββββββββββββ β
β COMPLETED βββββββββββββββββββββββββββββββββββββββββββββββββββ
β (TEST_COMPLETE) β
βββββββββββββββββββ
Data Flow
Command Flow (ESP-NOW β Motor)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Remote Controller
β
β ESP-NOW Packet [hdr:6][payload:N][crc:2]
βΌ
ESP-NOW Receiver (ISR) βββ espnowRecvCb()
β
β RawMsg (data + len)
βΌ
s_raw_recv_queue (FreeRTOS)
β
βΌ
recvTask() βββ handlePacket()
β β’ CRC validation
β β’ Header parsing
β β’ Payload extraction
βΌ
ProtoEvent {type, data}
β
βΌ
g_espnowQueue (FreeRTOS)
β
βΌ
espnow_command_task()
β β’ ConfigSet β update g_settings
β β’ CommandStart β RequestStart()
β β’ CommandPause β g_cancel_bounds, Stop()
β β’ etc.
βΌ
bounds_finding_task() or motion_control_task()
β
β g_driver->homing.FindBounds() or g_motion->Update()
βΌ
TMC51x0 Driver (SPI)
β
βΌ
Motor Hardware
Status Flow (Motor β Remote)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
motion_control_task() or bounds_finding_task()
β
β Motion status (cycles, position, state)
βΌ
g_motion->GetStatus()
β
βΌ
status_update_task() (every 1000ms if RUNNING/BOUNDS_FINDING)
β
β EspNowReceiver::send_status_update(cycle, state)
βΌ
sendPacketToUi(MsgType::StatusUpdate, StatusPayload)
β β’ Build header
β β’ Copy payload
β β’ Calculate CRC
β β’ Place CRC at correct offset
βΌ
esp_now_send(s_ui_board_mac, buffer, len)
β
β ESP-NOW Packet [hdr:6][StatusPayload:6][crc:2]
βΌ
Remote Controller
Thread Safety
Mutex Protection
- TMC Driver Access: Protected by
Esp32TmcMutexfor all SPI operations - Motion Controller: Internal mutex for state access
Queue Communication
- ProtoEvent Queue: ESP-NOW events to command task
- Raw RX Queue: ISR to receive task (ISR-safe xQueueSendFromISR)
RAII Guards
1
2
3
4
5
// Automatic mutex locking/unlocking
{
std::lock_guard<std::mutex> lock(motion_mutex_);
// Safe access to motion state
}
Error Handling
| Error Type | Detection | Response |
|---|---|---|
| Protocol CRC | CRC mismatch | Packet dropped, log warning |
| Protocol Version | Version check | Packet dropped, log warning |
| Bounds Finding Timeout | Timer expiration | Error state, report to remote |
| Bounds Not Found | Library result | Error state, report to remote |
| Motion Error | State validation | Error state, motor disabled |
Memory Management
| Type | Usage | Notes |
|---|---|---|
| Stack | Task stacks (4-8KB each) | Sized for worst-case recursion |
| Heap | FreeRTOS queues | Created at init, fixed size |
| Static | Global state, settings, driver | Single instances |
| BSS | Uninitialized globals | Zero-initialized at startup |
Performance Characteristics
| Metric | Value | Notes |
|---|---|---|
| Motion Update Rate | 100 Hz | 10ms period in motion_control_task |
| Status Update Rate | 1 Hz | 1000ms period in status_update_task |
| ESP-NOW Latency | < 10ms | Event-driven, low latency |
| Command Response | < 50ms | Including bounds check |
| Bounds Finding | 5-30s | Depends on search speed/span |
Extension Points
- New Motion Patterns: Extend
FatigueTestMotionclass- Add new motion profile generators
- Implement custom cycle counting logic
- New Commands: Extend protocol
- Add to
MsgTypeenum in both projects - Implement handler in
espnow_command_task
- Add to
- New Settings: Extend
TestUnitSettings- Add field to struct
- Update CONFIG_SET handler
- Update remote controller payload
- New Status Fields: Extend
StatusPayload- Add fields to struct
- Update send_status_update()
- Update remote controller handler
Dependencies
| Dependency | Version | Purpose |
|---|---|---|
| ESP-IDF | 5.x | FreeRTOS, WiFi, ESP-NOW |
| TMC51x0 Driver Library | Latest | Motor control, homing |
| FreeRTOS | (ESP-IDF) | Task management, queues |