24 KiB
CONFIGURATION, WORKFLOWS & IMPLEMENTATION GUIDE
Document: Part 5 of Robot Tuning System Architecture
Coverage: Default configurations, tuning workflows, implementation phases, and testing strategy
DEFAULT CONFIGURATIONS
All default values with detailed justifications.
1. Robot Physical Configuration
public static class DefaultConfigurations
{
public static RobotPhysicalConfig Physical => new()
{
// Wheelbase: Distance between left and right wheels
// Typical for small indoor robot: 0.3-0.5m
// Affects: Turning radius, stability
Wheelbase = 0.35f, // meters
// Wheel radius: Affects odometry calculations
// Typical: 0.05-0.1m for small robots
WheelRadius = 0.075f, // meters
// Max linear velocity: User-specified
MaxLinearVelocity = 1.5f, // m/s
// Max angular velocity: Calculated from max linear velocity
// ω_max ≈ 2 * v_max / wheelbase
// Conservative estimate: 2 * 1.5 / 0.35 ≈ 8.57 rad/s
// Use 6 rad/s for safety margin (~343°/s)
MaxAngularVelocity = 6.0f, // rad/s
// Max linear acceleration: For smooth motion
// 1.0 m/s² means 0 → 1.5 m/s in 1.5 seconds
// Typical range: 0.5-2.0 m/s²
MaxLinearAcceleration = 1.0f, // m/s²
// Max angular acceleration: User-specified
MaxAngularAcceleration = 1.0f, // rad/s²
// Robot mass: Estimated for small mobile robot
Mass = 25.0f // kg
};
}
2. Control Timing Configuration
public static ControlTimingConfig Timing => new()
{
// Control loop frequency: 50Hz (20ms per cycle)
// Justification:
// - 10Hz: Too slow, robot will oscillate
// - 50Hz: Optimal for indoor navigation (balance performance/CPU)
// - 100Hz: Better but requires more CPU, marginal gains
// - 200Hz+: Overkill for this application
ControlLoopFrequency = 50, // Hz
// Encoder sampling: Match or exceed control frequency
EncoderSamplingRate = 50, // Hz
// Motor command rate: Match control frequency
MotorCommandRate = 50 // Hz
};
3. PID Controller Configuration
public static VelocityPIDConfig PID => new()
{
// Kp: Proportional gain
// Higher Kp = faster response but more overshoot
// Starting point: 0.8 (moderate response)
// Tuning range: 0.1-5.0
Kp = 0.8f,
// Ki: Integral gain
// Eliminates steady-state error
// Keep small to avoid windup
// Starting point: 0.1
// Tuning range: 0.0-2.0
Ki = 0.1f,
// Kd: Derivative gain
// Dampens oscillations, smooths response
// Starting point: 0.05 (gentle damping)
// Tuning range: 0.0-1.0
Kd = 0.05f,
// Velocity limits
MaxVelocity = 1.5f, // m/s (from physical config)
MinVelocity = 0.1f, // m/s (minimum for robot to move)
// Anti-windup: Prevent integral term from growing unbounded
IntegralWindupLimit = 0.5f, // m/s
// Output saturation: Ensure output stays within limits
OutputSaturationEnabled = true
};
PID Tuning Guidelines:
- Start with Kp only (Ki=0, Kd=0), increase until oscillation
- Reduce Kp to 60% of oscillation value
- Add Kd to dampen remaining oscillation
- Add Ki last, only if steady-state error exists
4. Velocity Estimator Configuration
public static VelocityEstimatorConfig Estimator => new()
{
// Alpha filter: Exponential moving average for encoder
// Lower α (0.1-0.2): More filtering, more lag
// Higher α (0.3-0.4): Less filtering, more responsive
// Recommended: 0.3 for balance
AlphaFilter = 0.3f,
// Blend ratio bounds
MinBlendRatio = 0.15f, // Min 15% model, 85% encoder
MaxBlendRatio = 0.8f, // Max 80% model, 20% encoder
DefaultBlendRatio = 0.6f, // Start with 60% model
// Adaptive blending thresholds
GoodTrackingThreshold = 0.12f, // < 12% error
ModerateTrackingThreshold = 0.3f, // < 30% error
// CORRECTED blend ratios (based on architecture review):
// Good tracking → trust encoder more (model prediction matches reality)
GoodTrackingBlend = 0.3f, // 30% model, 70% encoder
// Moderate tracking → balanced
ModerateTrackingBlend = 0.5f, // 50-50 blend
// Poor tracking → trust model more (encoder may have slip)
PoorTrackingBlend = 0.7f, // 70% model, 30% encoder
// Confidence decay: How fast confidence drops
// 0.98 = slow decay (1% per cycle at 50Hz = ~2s to halve)
// 0.95 = medium decay
// 0.90 = fast decay
ConfidenceDecayRate = 0.98f,
// Minimum confidence floor
MinConfidence = 0.3f // Never go below 30%
};
5. Pure Pursuit Configuration
public static PurePursuitConfig PurePursuit => new()
{
// Lookahead minimum: Smallest lookahead distance
// Too small: Oscillation, overshoot corners
// Too large: Cuts corners, poor tracking
// Recommended: 0.2-0.4m for indoor robot
LookaheadMin = 0.3f, // meters
// Kdd: Lookahead velocity scaling factor
// lookahead = LookaheadMin + Kdd * |velocity|
// Kdd = 1.0 means 1 second lookahead time
// Kdd = 0.5 means 0.5 second lookahead
// Recommended: 0.8-1.5
Kdd = 1.0f, // seconds
// Lookahead maximum: Cap lookahead distance
// Prevents looking too far ahead at high speeds
// Recommended: 1.5-3.0m
LookaheadMax = 2.0f // meters
};
Pure Pursuit Tuning Guidelines:
- Increase Kdd for smoother, more predictive tracking
- Decrease Kdd for tighter, more reactive tracking
- Increase LookaheadMin if robot oscillates
- Decrease LookaheadMin if robot cuts corners
6. Path Following Configuration
public static PathFollowingConfig PathFollowing => new()
{
// Waypoint tolerance: How close to consider waypoint "reached"
WaypointTolerance = 0.15f, // 15cm
// Final goal tolerance: Tighter tolerance for final goal
FinalGoalTolerance = 0.05f, // 5cm
// Goal heading tolerance: Acceptable heading error at goal
GoalHeadingTolerance = 5f * MathF.PI / 180f, // 5 degrees
// Stop distance: When to start preparing to stop
StopDistance = 0.1f, // 10cm before goal
// Stop velocity: Threshold to consider robot "stopped"
StopVelocity = 0.05f // 5cm/s
};
7. Safety Configuration
public static SafetyConfig Safety => new()
{
// Max cross-track error before abort
// 0.5m is reasonable for 10x20m indoor space
MaxCrossTrackError = 0.5f, // meters
// Max heading error before abort
// 45° means robot is severely off course
MaxHeadingError = 45f * MathF.PI / 180f, // radians
// Sustained error duration before abort
// 3 seconds allows recovery from temporary issues
MaxTrackingErrorDuration = 3000, // milliseconds
// Obstacle safety distances (for future sensors)
MinObstacleDistance = 0.3f, // 30cm emergency stop
SafetyStopDistance = 0.5f, // 50cm slow down
// Emergency deceleration limit
EmergencyStopDeceleration = 2.0f // m/s²
};
8. Acceptance Criteria Configuration
public static AcceptanceCriteria Criteria => new()
{
// PRIMARY: Tracking Accuracy (50% weight)
// Cross-track error RMS: 10cm is good for indoor robot
MaxCrossTrackErrorRMS = 0.10f, // meters
// Peak CTE: Allow double RMS as occasional spike
MaxCrossTrackErrorPeak = 0.20f, // meters
// Heading error: 10° RMS is acceptable
MaxHeadingErrorRMS = 10f * MathF.PI / 180f, // radians
// Goal position error: 5cm final accuracy
MaxGoalPositionError = 0.05f, // meters
// Goal heading error: 5° final accuracy
MaxGoalHeadingError = 5f * MathF.PI / 180f, // radians
// SECONDARY: Smoothness (30% weight)
// Max jerk: 5 m/s³ is smooth for human comfort
MaxJerk = 5.0f, // m/s³
// Max angular jerk: 10 rad/s³
MaxAngularJerk = 10.0f, // rad/s³
// TERTIARY: Efficiency (20% weight)
// Path length ratio: <15% deviation from optimal
MaxPathLengthRatio = 1.15f, // 115% of optimal
// Success rate: 90% of runs should pass
MinSuccessRate = 0.90f // 90%
};
9. Scoring Weights
public static ScoringWeights Weights => new()
{
// How much each category contributes to overall score
TrackingAccuracy = 0.5f, // 50%
Smoothness = 0.3f, // 30%
Efficiency = 0.2f // 20%
};
10. Parameter Bounds
public static class ParameterBounds
{
// PID bounds
public static Range KpRange = new(0.1f, 5.0f);
public static Range KiRange = new(0.0f, 2.0f);
public static Range KdRange = new(0.0f, 1.0f);
// Estimator bounds
public static Range AlphaFilterRange = new(0.05f, 0.5f);
public static Range BlendRatioRange = new(0.1f, 0.9f);
public static Range ConfidenceDecayRange = new(0.90f, 0.99f);
// Pure Pursuit bounds
public static Range KddRange = new(0.3f, 2.0f);
public static Range LookaheadMinRange = new(0.1f, 0.5f);
public static Range LookaheadMaxRange = new(0.5f, 3.0f);
// Validation rules
public static List<ValidationRule> Rules => new()
{
new ValidationRule
{
Name = "LookaheadOrdering",
Check = (p) => p.PurePursuit.LookaheadMax > p.PurePursuit.LookaheadMin,
Message = "LookaheadMax must be greater than LookaheadMin"
},
new ValidationRule
{
Name = "BlendRatioOrdering",
Check = (p) => p.Estimator.GoodTrackingBlend <= p.Estimator.PoorTrackingBlend,
Message = "GoodTrackingBlend should be less than PoorTrackingBlend"
},
new ValidationRule
{
Name = "VelocityLimit",
Check = (p) => p.PID.MaxVelocity <= p.Physical.MaxLinearVelocity,
Message = "PID MaxVelocity cannot exceed physical limit"
}
};
}
TUNING WORKFLOWS
Detailed step-by-step workflows for different tuning scenarios.
Workflow 1: Quick Start (First-Time User)
Goal: Get robot moving with default settings and validate basic functionality.
Steps:
-
Load Default Configuration (5 min)
- Open dashboard
- Navigate to Configuration → Robot Settings
- Verify physical parameters (wheelbase, wheel radius)
- Click "Load Default Preset"
-
Run Baseline Test (2 min)
- Select Test Scenario: "Straight Line 10m"
- Click "Run Test"
- Observe real-time visualization
- Wait for completion
-
Review Results (3 min)
- Check overall score
- Identify which metrics fail (if any)
- Note: CTE RMS, jerk, smoothness
-
Decision Point:
- Score > 80: Proceed to Workflow 2 (test other trajectories)
- Score 60-80: Proceed to Workflow 3 (manual tuning)
- Score < 60: Check robot hardware, retry
Expected Outcome: Baseline performance established, ready for tuning.
Workflow 2: Multi-Scenario Validation
Goal: Test current configuration across all trajectory types.
Steps:
-
Setup Batch Test (2 min)
- Navigate to Tuning → Parameter Comparison
- Select all scenarios:
- Straight Line 10m
- Circle 2m Radius
- Circle 0.5m Radius
- Select current parameter set
- Click "Run Batch"
-
Monitor Progress (10-15 min)
- Watch each test in sequence
- Note any failures or safety violations
-
Analyze Comparison (5 min)
- View comparison table
- Identify weakest scenario
- Check metric breakdown per scenario
-
Decision Point:
- All scenarios pass: Configuration is robust
- One scenario fails: Tune for that specific case
- Multiple scenarios fail: Need general tuning (Workflow 3)
Workflow 3: Manual Iterative Tuning
Goal: Hand-tune parameters to improve specific metrics.
Steps:
Phase 1: Improve Tracking Accuracy (if CTE RMS > 0.10m)
-
Diagnose Issue:
- View trajectory plot
- Check if robot overshoots or undershoots corners
- Check if error is consistent or oscillating
-
If Robot Overshoots (cuts corners):
- Decrease Pure Pursuit LookaheadMin: 0.3 → 0.25
- Decrease Kdd: 1.0 → 0.8
- Run test, check improvement
-
If Robot Undershoots (goes wide):
- Increase Pure Pursuit LookaheadMin: 0.3 → 0.35
- Increase Kdd: 1.0 → 1.2
- Run test, check improvement
-
If Robot Oscillates:
- Increase PID Kd: 0.05 → 0.15 (more damping)
- Increase Estimator AlphaFilter: 0.3 → 0.4 (more smoothing)
- Run test, check improvement
-
If Robot is Sluggish:
- Increase PID Kp: 0.8 → 1.2 (faster response)
- Run test, check for overshoot
Phase 2: Improve Smoothness (if Jerk > 5.0 m/s³)
-
Increase Damping:
- Increase PID Kd: current → +0.1
- Run test
-
Smooth Velocity Estimates:
- Decrease Estimator AlphaFilter: 0.3 → 0.2
- Run test
-
Reduce Aggressiveness:
- Decrease PID Kp: current → -0.2
- Run test
Phase 3: Verify and Save
-
Run Full Validation:
- Test all scenarios with new parameters
- Ensure no regressions
-
Save Configuration:
- Name: "Tuned_[Date]_v1"
- Add description of changes
- Click "Save"
Iteration: Repeat phases as needed, aiming for <5 iterations.
Workflow 4: Automated Optimization (Advanced)
Goal: Use algorithm to find optimal parameters automatically.
Steps:
-
Configure Optimization (5 min)
- Navigate to Tuning → Auto Tuning
- Select algorithm: Bayesian Optimization
- Select parameters to tune:
- ☑ PID: Kp, Ki, Kd
- ☑ Pure Pursuit: Kdd
- ☐ Estimator: (keep fixed for first run)
- Set constraints:
- Max iterations: 30
- Early stopping: 1% improvement threshold
-
Define Objective (2 min)
- Primary metric: Cross-Track Error RMS
- Secondary metric: Max Jerk (weight: 0.3)
- Test scenario: Circle 2m Radius
-
Start Optimization (30-60 min)
- Click "Start Optimization"
- Monitor progress dashboard
- View live updates of best parameters found
-
Review Results (10 min)
- Check final parameters
- Compare to baseline
- Review improvement %
-
Validate on Other Scenarios (15 min)
- Run batch test with optimized parameters
- Ensure no regressions on other trajectories
-
Save or Iterate:
- If satisfied: Save as "Optimized_v1"
- If not: Adjust weights, re-run optimization
Workflow 5: A/B Testing Configurations
Goal: Compare two parameter sets side-by-side.
Steps:
-
Select Configurations (2 min)
- Config A: "Default"
- Config B: "Tuned_v1"
-
Choose Test Scenario (1 min)
- Straight Line 10m
-
Run Comparison (5 min)
- Click "Run Comparison"
- System runs both tests sequentially
-
Analyze Results (5 min)
- View side-by-side metrics table
- Check trajectory overlay plot
- Identify winner
-
Statistical Significance (optional)
- Run 10 trials each
- Compare mean ± std deviation
- Determine if difference is significant
IMPLEMENTATION PHASES
Phased approach to building the system, prioritized by value and complexity.
Phase 0: MVP (Weeks 1-3)
Goal: Core functionality for manual tuning.
Features:
- ✅ Single test execution
- ✅ Manual parameter adjustment UI
- ✅ Real-time visualization (2D trajectory)
- ✅ Basic metrics calculation
- ✅ Save/load configurations
- ✅ Data logging
Deliverables:
- Working Blazor dashboard
- Integrated controllers (PID, Estimator, Pure Pursuit)
- Basic test executor
- SQLite database with core tables
- Real-time SignalR updates
Tech Stack:
- Blazor Server
- Entity Framework Core + SQLite
- SignalR
- Plotly.NET for charts
Testing:
- Unit tests for controllers
- Integration test for one full test run
- Manual UI testing
Success Criteria:
- User can run a test and see results
- Parameters can be adjusted and re-run
- Metrics are calculated correctly
Phase 1: Enhanced Tuning (Weeks 4-6)
Goal: Multi-scenario testing and comparison.
Features:
- ✅ Batch testing
- ✅ Configuration comparison
- ✅ Test history viewer
- ✅ Safety monitoring with abort
- ✅ Parameter validation
- ✅ CSV export
Deliverables:
- Batch test executor
- Comparison UI components
- Enhanced database queries
- Safety monitor implementation
- Report generation (HTML/CSV)
Testing:
- Batch test with 3 scenarios
- Comparison test with 3 configs
- Safety violation test
Success Criteria:
- Batch tests complete without manual intervention
- Comparison clearly shows best configuration
- Safety system aborts on violations
Phase 2: Advanced Analytics (Weeks 7-9) - OPTIONAL
Goal: Deep insights and semi-automated tuning.
Features:
- ⭕ Statistical analysis
- ⭕ Trend analysis over time
- ⭕ Parameter sensitivity analysis
- ⭕ Tuning suggestions
- ⭕ PDF report generation
Deliverables:
- Statistics calculator
- Trend visualization
- Suggestion engine (rule-based)
- PDF generator
Testing:
- Historical data analysis (50+ tests)
- Suggestion accuracy validation
Success Criteria:
- Trends clearly visible
- Suggestions improve results
Phase 3: Automated Optimization (Weeks 10-13) - FUTURE
Goal: Hands-off parameter optimization.
Features:
- ❌ Grid search
- ❌ Random search
- ❌ Bayesian optimization
- ❌ Genetic algorithm
- ❌ Multi-objective optimization
Deliverables:
- Optimization framework
- Multiple algorithm implementations
- Hyperparameter tuning for optimizers
- Parallel evaluation (if multiple robots)
Complexity: Very High (requires ML libraries)
Testing:
- Benchmark against manual tuning
- Convergence tests
- Robustness tests
Success Criteria:
- Automated optimization finds better params than manual in <1 hour
- Reproducible results
TESTING STRATEGY
Comprehensive testing at all levels.
1. Unit Tests
Coverage Target: >80% for domain logic
Key Tests:
// PID Controller Tests
[Fact]
public void PIDController_ProportionalOnly_CorrectOutput()
{
var config = new VelocityPIDConfig { Kp = 1.0f, Ki = 0, Kd = 0 };
var pid = new PIDController(config);
var output = pid.Calculate(error: 1.0f, dt: 0.02f);
Assert.Equal(1.0f, output, precision: 2);
}
[Fact]
public void PIDController_IntegralWindup_Clamped()
{
var config = new VelocityPIDConfig
{
Kp = 0,
Ki = 1.0f,
Kd = 0,
IntegralWindupLimit = 0.5f
};
var pid = new PIDController(config);
// Accumulate large error
for (int i = 0; i < 100; i++)
pid.Calculate(error: 1.0f, dt: 0.02f);
var output = pid.Calculate(error: 1.0f, dt: 0.02f);
Assert.True(output <= 0.5f);
}
// Velocity Estimator Tests
[Fact]
public void VelocityEstimator_GoodTracking_TrustsEncoder()
{
var config = DefaultConfigurations.Estimator;
var estimator = new VelocityEstimator(config, new VelocitySignalProcessingConfig());
var vHybrid = estimator.EstimateVelocity(
vCmd: 1.0f,
vActual: 0.95f, // Close to command (good tracking)
dt: 0.02f
);
// Should blend more toward encoder (0.95) than model
Assert.True(vHybrid > 0.93f && vHybrid < 0.97f);
}
// Pure Pursuit Tests
[Fact]
public void PurePursuit_LookaheadScalesWithVelocity()
{
var config = new PurePursuitConfig
{
LookaheadMin = 0.3f,
Kdd = 1.0f,
LookaheadMax = 2.0f
};
var pp = new PurePursuitController(config);
var path = CreateStraightLinePath(10);
var pose = new Pose2D(0, 0, 0);
pp.Calculate(pose, velocity: 0.5f, confidence: 1.0f, path);
var lookahead1 = pp.GetLookaheadDistance();
pp.Calculate(pose, velocity: 1.0f, confidence: 1.0f, path);
var lookahead2 = pp.GetLookaheadDistance();
Assert.True(lookahead2 > lookahead1);
}
2. Integration Tests
[Fact]
public async Task FullTestRun_StraightLine_Completes()
{
// Arrange
var scenario = CreateStraightLineScenario(10);
var parameters = DefaultConfigurations.GetDefaultPreset();
var orchestrator = CreateOrchestrator();
// Act
var result = await orchestrator.RunSingleTest(scenario, parameters);
// Assert
Assert.Equal(TestStatus.Completed, result.Status);
Assert.NotNull(result.Metrics);
Assert.True(result.Metrics.CrossTrackErrorRMS < 0.20f);
}
[Fact]
public async Task SafetyMonitor_ExcessiveCTE_AbortsTest()
{
// Arrange
var scenario = CreateCircleScenario(0.5f); // Tight circle
var parameters = CreateBadParameters(); // Intentionally bad
var orchestrator = CreateOrchestrator();
// Act
var result = await orchestrator.RunSingleTest(scenario, parameters);
// Assert
Assert.Equal(TestStatus.Aborted, result.Status);
Assert.True(result.SafetyViolations.Any(v => v.Type == ViolationType.CrossTrackError));
}
3. Performance Tests
[Fact]
public void ControlLoop_MaintainsFrequency()
{
var executor = CreateTestExecutor();
var scenario = CreateStraightLineScenario(5);
var parameters = DefaultConfigurations.GetDefaultPreset();
var timestamps = new List<long>();
executor.ExecuteAsync(
onStateUpdate: state => timestamps.Add(state.TimestampMs)
).Wait();
// Calculate actual frequency
var intervals = timestamps.Zip(timestamps.Skip(1), (a, b) => b - a);
var avgInterval = intervals.Average();
var actualFrequency = 1000.0 / avgInterval;
Assert.InRange(actualFrequency, 48, 52); // 50Hz ± 2Hz
}
4. End-to-End Tests
Manual Test Plan:
-
Happy Path Test
- Load default config
- Run straight line test
- Verify metrics displayed
- Save configuration
- Reload and verify
-
Error Handling Test
- Set invalid parameter (Kp = 100)
- Attempt to run test
- Verify error message shown
- Verify test doesn't start
-
Real-time Update Test
- Start test
- Verify UI updates at ~10Hz
- Pause test
- Verify pause works
- Resume and complete
-
Comparison Test
- Create 2 configs
- Run comparison
- Verify side-by-side display
- Export results
DEPLOYMENT CHECKLIST
Pre-deployment validation:
- All unit tests pass
- Integration tests pass
- Performance tests pass
- Manual E2E tests completed
- Database migrations created
- Default data seeded
- Configuration files reviewed
- Robot hardware tested
- Emergency stop tested
- Documentation complete
- User manual created
This completes the Configuration, Workflows & Implementation Guide.