Navigation
Strategy: RC-First
The rulebook permits remote-controlled robots. RC mode is the primary competition mode; the autonomous FSM is a stretch goal demoed only if reliable.
| Mode | How to enter | What it does |
|---|---|---|
| RC (primary) | Hold BOOT button at power-on | WiFi AP + phone joystick page; operator drives, samples, tags sectors |
| Autonomous (stretch) | Normal power-on | Wander pattern with zone auto-detection, 8-min hard cap |
The WiFi AP and web server run in both modes so judges can always pull /data immediately after a run.
RC Run Procedure
- Power on with BOOT held → connect phone to
RobotAP→ open192.168.4.1. - Drive to a zone with the D-pad. Select the current sector (S1–S4) on the page.
- Stop next to the zone (never over a water slot). Press Sample Water or Sample Soil.
- The arm deploys, reads, retracts; the reading is logged with your sector tag and printed to serial.
- Repeat for all 12 zones. Press End Run to finalise
results.json.
Position Estimation (and its limits)
The robot has no wheel encoders. Position is estimated as:
- Heading — MPU6050 DMP absolute yaw, zeroed at power-on. Reliable.
- Distance — commanded motor speed × time (
MM_PER_SEC_AT_DRIVE, calibrated by timing a 1m drive). Rough.
// position.cpp — speed-model update, every 20ms
float v = (cmdL_mm_s + cmdR_mm_s) / 2.0f; // commanded, not measured
pos.x_mm += v * dt * cosf(pos.heading_rad);
pos.y_mm += v * dt * sinf(pos.heading_rad);
The estimate feeds the path[] log for visualisation only. It is never used for safety decisions — zone detection (colour) and wall detection (ToF) are always live sensor reads.
If the robot gets stuck, officials place it at the arena centre. Heading survives (IMU is absolute); the position estimate does not. Samples and sector tags remain valid — the path plot is best-effort.
Autonomous FSM (stretch goal)
INIT
│ Zero IMU heading · reset sample count · start 8-min timer
↓
SWEEP ← wander with IMU heading hold
│ isWaterZone() (+ lockout) → POND_SAMPLE
│ isSoilPatch() (+ lockout) → MEASURE_SOIL
│ ToF < WALL_STOP_MM → bounce ~135° to new heading
│ 12 samples or 8 min → COMPLETE
↓
POND_SAMPLE
│ stop → arm 0° → settle → read NTU → arm 90° → log
↓
POND_BACKOFF
│ REVERSE for POND_BACKOFF_MS — wheels never cross the recessed slot
│ turn away → restart detection lockout → SWEEP
↓
MEASURE_SOIL
│ stop → arm 180° → settle → read % → arm 90° → log → new heading → SWEEP
↓
COMPLETE
stop · arm neutral · finalise results.json · LED blink
web server stays alive — judges pull /data immediately
Key mechanisms
| Mechanism | Constant | Why |
|---|---|---|
| 8-minute hard cap | RUN_TIME_LIMIT_MS |
Exceeding the run limit costs −5 pts |
| Re-sample lockout | SAMPLE_LOCKOUT_MS |
No coordinates without encoders — a driving-time lockout prevents re-sampling the zone just measured |
| Pond backoff | POND_BACKOFF_MS |
Water slots are recessed wheel traps; the robot reverses away after sampling, never drives over |
| Wall bounce | WALL_STOP_MM |
VL53L0X stops the robot before the octagon wall; heading changes ~135°, alternating direction |
Sector labels in autonomous mode
Without localization the FSM can only estimate sector by collection order (samples/3 + 1). Accurate sector labels come from RC mode, where the operator selects the sector before each sample. This is a deliberate tradeoff — and another reason RC is the primary mode.