Bounds Finding Cache System

Overview

The Bounds Caching System allows independent bounds finding, keeping the motor ready for immediate test starts. This improves workflow efficiency by eliminating redundant bounds finding when running multiple tests in succession.

Key Features

  1. Independent Bounds Finding: Run bounds command separately from test start
  2. Time-Based Validity: Bounds remain valid for a configurable window (default: 2 minutes)
  3. Motor State Management: Motor stays energized during validity window, de-energizes after timeout
  4. Automatic De-energization: Prevents motor overheating during idle periods
  5. Skip Redundant Finding: start command uses cached bounds if still valid

Commands

bounds

Run bounds finding independently without starting the test.

1
2
3
4
5
6
7
8
9
10
> bounds
╔══════════════════════════════════════════════════════════════════════════════╗
β•‘                              BOUNDS FINDING                                   β•‘
╠══════════════════════════════════════════════════════════════════════════════╣
β•‘ Bounds finding started...                                                    β•‘
β•‘ Motor will stay energized after completion.                                  β•‘
β•‘ Validity window: 2 minutes                                                   β•‘
β•‘                                                                              β•‘
β•‘ Run 'start' within validity window to skip bounds finding.                   β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

start (with cache)

When bounds are cached and valid:

1
2
3
> start
[FatigueTestUnit] Using cached bounds (valid for 85 more seconds)
[FatigueTestUnit] Test started immediately (no bounds finding)

When bounds are expired or not found:

1
2
3
> start
[FatigueTestUnit] Bounds not cached or expired - running bounds finding
[FatigueTestUnit] Starting bounds finding...

status (shows cache info)

1
2
3
4
5
6
7
8
9
10
11
12
13
> status
╔══════════════════════════════════════════════════════════════════════════════╗
β•‘                              MOTION STATUS                                    β•‘
╠══════════════════════════════════════════════════════════════════════════════╣
β•‘ State:              IDLE                                                     β•‘
β•‘ Bounded:            YES                                                      β•‘
β•‘ Frequency:          0.50 Hz                                                  β•‘
β•‘ ...                                                                          β•‘
β•‘                                                                              β•‘
β•‘ BOUNDS CACHE:                                                                β•‘
β•‘   Status:           Valid (85 sec remaining)                                 β•‘
β•‘   Motor:            Energized (ready for start)                              β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

State Diagram

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
38
39
40
                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                          β”‚ Motor De-energized  β”‚
                          β”‚  Bounds Invalid     β”‚
                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                     β”‚
           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
           β”‚                         β”‚                         β”‚
    bounds command             start command           config change
           β”‚                         β”‚                         β”‚
           β–Ό                         β–Ό                         β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                 β”‚
    β”‚ BOUNDS       β”‚          β”‚ BOUNDS       β”‚                 β”‚
    β”‚ FINDING      β”‚          β”‚ FINDING      β”‚                 β”‚
    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜          β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚
           β”‚                         β”‚                         β”‚
    bounds found              bounds found                     β”‚
           β”‚                         β”‚                         β”‚
           β–Ό                         β–Ό                         β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                 β”‚
    β”‚ IDLE             β”‚      β”‚ RUNNING      β”‚                 β”‚
    β”‚ Motor Energized  β”‚      β”‚ Test Active  β”‚                 β”‚
    β”‚ Timer Started    β”‚      β”‚ Timer Paused β”‚                 β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚
             β”‚                       β”‚                         β”‚
     β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”        test complete                    β”‚
     β”‚               β”‚               β”‚                         β”‚
 timeout          start              β”‚                         β”‚
   2min          command             β”‚                         β”‚
     β”‚               β”‚               β”‚                         β”‚
     β–Ό               β–Ό               β–Ό                         β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                 β”‚
β”‚ Motor      β”‚  β”‚ RUNNING  β”‚  β”‚ Motor        β”‚                 β”‚
β”‚ De-energizedβ”‚  β”‚ (no      β”‚  β”‚ De-energized β”‚                 β”‚
β”‚ Bounds     β”‚  β”‚ bounds   β”‚  β”‚ Bounds Valid β”‚                 β”‚
β”‚ Expired    β”‚  β”‚ needed)  β”‚  β”‚ (for next    β”‚                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚ quick start) β”‚                 β”‚
                              β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚
                                     β”‚                         β”‚
                                timeout orβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                next start

Configuration

Default Validity Window

1
2
3
namespace BoundsCache {
    static constexpr uint32_t DEFAULT_VALIDITY_MINUTES = 2;
}

Changing Validity at Runtime

1
2
// Set validity to 5 minutes
BoundsCache::SetValidityMinutes(5);

Compile-Time Configuration

Modify DEFAULT_VALIDITY_MINUTES in main.cpp to change the default:

1
static constexpr uint32_t DEFAULT_VALIDITY_MINUTES = 5; // 5 minutes

API Reference

BoundsCache Namespace

Function Description
Init() Initialize the bounds cache system (create timer)
AreBoundsValid() Check if cached bounds are still valid
GetRemainingValiditySec() Get seconds remaining in validity window
MarkBoundsFound() Mark bounds as found, start de-energize timer
CancelDeenergizeTimer() Cancel timer (e.g., when test starts)
InvalidateBounds() Force invalidation (e.g., on config change)
SetValidityMinutes(uint32_t) Change validity window

Global Variables

Variable Description
g_bounds_validity_us Validity window in microseconds
g_bounds_timestamp_us Timestamp when bounds were last found
g_motor_energized_for_bounds Whether motor is energized from bounds finding
g_deenergize_timer ESP timer handle for de-energize callback

Workflow Examples

Quick Iteration Workflow

For testing different settings rapidly:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1. Find bounds once
> bounds

# 2. Run first test
> start

# 3. Wait for completion or stop
> stop

# 4. Adjust settings
> set -f 0.7

# 5. Start again immediately (bounds still valid)
> start

Standard Test Workflow

For production testing:

1
2
3
4
5
6
7
8
# 1. Configure test parameters
> set -f 0.5 -c 1000 -b -60 60

# 2. Start test (bounds found automatically)
> start

# 3. Monitor progress
> status

Pre-Flight Check Workflow

For verification before actual testing:

1
2
3
4
5
6
7
8
# 1. Run bounds to verify mechanism works
> bounds

# 2. Check status shows valid bounds
> status

# 3. If satisfied, start test
> start

Timing Details

De-energize Timer

  • Type: One-shot ESP timer
  • Resolution: Microseconds (from esp_timer_get_time())
  • Callback context: ESP timer task (not ISR safe, can call motor functions)

Critical Timing Scenarios

Scenario Timer Behavior
bounds completes Timer started for 2 minutes
start with valid cache Timer cancelled, test runs
Timer expires (idle) Motor de-energized, bounds marked expired
stop during test Timer NOT restarted (bounds stay valid)
Config change Timer cancelled, bounds invalidated

Safety Considerations

Motor Heating Prevention

The de-energize timer ensures the motor doesn’t remain energized indefinitely:

  1. After bounds finding, motor stays energized (holding torque applied)
  2. If no test starts within validity window, motor is disabled
  3. This prevents motor and driver overheating during extended idle periods

Power-On State

At boot:

  • Motor starts disabled
  • Bounds are invalid
  • First start or bounds command will energize and find bounds

Error Recovery

If bounds finding fails:

  • Motor is disabled immediately
  • Bounds remain invalid
  • Next start will retry bounds finding

Troubleshooting

Bounds Keep Expiring Too Fast

Cause: Validity window too short for your workflow.

Solution: Increase validity window:

1
BoundsCache::SetValidityMinutes(5); // 5 minutes

Motor De-energizes Unexpectedly

Cause: Validity timer expired.

Solution: Run bounds again or start test before timeout.

Start Runs Bounds Even Though Recently Found

Possible Causes:

  1. Config was changed (invalidates bounds)
  2. Timer expired
  3. Motor was manually disabled

Solution: Check status command for bounds cache state.

Motor Stays Energized After Stop

Expected Behavior: After stop, bounds remain valid but motor stays energized for the remaining validity window to allow quick restart.

To force motor disable: Wait for timeout, or change configuration.