🤖 Robot Tour C Simulator

Design your track layout (2m × 2.5m), place objects, and calculate your run score

📖 How to use the Simulator (Click to expand)

Purpose

This simulator is designed for the Science Olympiad "Robot Tour" event. It helps competitors design optimal track layouts, plan robot paths (including bonus actions like bottle drops and pickups), and calculate theoretical scores based on current event rules.

How to Use

  • Set Parameters: Choose your Tournament Type (Regionals, States, Nationals) to set the appropriate target time range.
  • Design Track: Use the "Track Tools" to place your Start, Target, Waypoints, and Bonuses. Click a tool then click the grid to place/toggle items.
  • Analyze & Simulate: The simulator calculates distance, required speed, and collision status in real-time. Use the "Simulate" button to watch the robot's movement.
  • Export Code: Click "Export to C++" to generate path segment code for your Arduino or ESP32 robot controller.
  • Score Calculator: Test "what-if" scenarios by entering time and distance results in the calculator section.

Pro Tips

• Waypoints snap to zone centers, edge midpoints, or corners to ensure competition legality.
• "Bottle Drop" adds a 30cm reverse move. "Bottle Pickup" ensures the turn ends exactly at the bottle.
• Adjust "Turn radius" to match your robot's physical steering capabilities.

Create Path

Waypoints snap to zone center, edge midpoint, or corner. Bottle Drop: reverse 30cm, then turn. Bottle Pickup: turn ends at waypoint, then straight. Click waypoint to remove.

Load / Save / Export Path

Event Parameters

Affects target time range and gate/bottle counts
60–80 (Regionals), 55–75 (States), 50–65 (Nationals)

Track Grid (200 cm × 250 cm)

Start
Path
Collision
Target
Gate Zone
Water Bottle
Bottle Drop (rev 30cm)
Bottle Pickup (turn ends at waypoint)
2×4 Obstacle

Select Path

Score Calculator

If unchecked: +50 pt penalty (easier run)

Results

Run Score
points (low wins)
Time Score
points
Distance Score
points
Bonuses
points

Max Score (current path)

Best possible score if robot follows waypoints exactly. Design path in Trajectory tab.

Add waypoints in Trajectory tab to see path.
Maximum score (perfect execution)
points (low wins)

Scoring Rules

Run Score = 200 + Time Score + Distance Score + Bonuses + Run Penalties

Time: Run < Target → (Target − Run) × 2   |   Run ≥ Target → (Run − Target)

Distance = 2.0 pt/cm × robot distance from target

Gate Bonus = −15 pts per gate entered  |  Water Bottle Bonus = −15 pts per bottle in gate zone

Penalties: Contact +70, No 2×4 +50, Stalling +20, Competition +150, Construction +300

Strategy

This logic runs in the simulator’s Realistic Mode and Stress Test. Use the path from Export C++ in the Trajectory tab.

Strategy: The robot follows a precomputed path of line and arc segments. Each loop, it compares its estimated position to the current segment, computes a target heading and cross-track error, then corrects with a steering term plus feedforward (velocity ratio on arcs). Motor commands are proportional to a base speed chosen to hit the target time. The robot trusts the gyro for heading and uses encoders for distance to update (x, y).

Sensors:

  • Wheel encoders — Distance traveled by each wheel (ΔdL, ΔdR) for odometry and speed.
  • IMU gyro — Heading θ (degrees). Used as the source of truth for rotation instead of integrating wheel diff, to avoid drift in turns.
Pseudocode (path follower)
LOOP (every 10–20 ms):

    seg = path[currentSegmentIdx]
    IF currentSegmentIdx >= pathLen: stop; DONE

    // 1. Target heading, cross-track error, segment done?
    IF seg == LINE:
        targetHeading = direction of line (+180° if reverse)
        crossTrackError = signed distance from robot to line
        segmentDone = past end or very close
    ELSE IF seg == ARC:
        targetHeading = tangent to circle at robot
        crossTrackError = (distToCenter − radius) × side
        segmentDone = past end angle

    IF segmentDone: currentSegmentIdx++; continue

    // 2. Steering correction (P control)
    headingError = targetHeading − estHeading
    steering = Kp_h × headingError − Kp_d × crossTrackError
    power = −1 if reverse else 1

    // 3. Feedforward for arcs (wheel speed ratio)
    leftFF, rightFF = 1, 1
    IF arc: set by (R ± W/2)/(R ∓ W/2), normalize avg

    // 4. Motor commands
    leftCmd  = (power × leftFF  − steering/100) × baseSpeed
    rightCmd = (power × rightFF + steering/100) × baseSpeed

    // 5. Odometry
    dDist = (ΔdLeft + ΔdRight) / 2
    estHeading = gyroθ
    estX += dDist × cos(estHeading)
    estY += dDist × sin(estHeading)

    drive(leftCmd, rightCmd)
Arduino/C++ code (path follower)

            

Run this before tuning the path follower. Hold still 2 s to measure IMU drift, then drive a square. Compares encoder heading with drift-corrected IMU to find additional variance.

Strategy: (1) Hold still 2 s—any change in IMU heading is drift; compute drift_rate (°/s). (2) Drive square (4 × 50 cm, 4 × 90°). Use imu_corrected = imu − drift_rate × time and compare to encoder heading. The residual (|imu_corrected − heading_enc|) is variance beyond drift—scale error, turn inconsistency, etc.

Sensors tested:

  • Encoders — Heading from wheel differential; position from dead reckoning.
  • IMU gyro — Raw heading. Drift measured when still; corrected during run for residual analysis.
Pseudocode (sensor test)
// 1. Drift calibration (robot still 2 s)
imu_start = readGyro()
delay(2000)
drift_rate = (readGyro() − imu_start) / 2.0   // °/s

// 2. Square run
FOR each of 4 sides:
    drive straight 50 cm, turn 90° CW
    imu_corrected = readGyro() − drift_rate × elapsed
    residual = |imu_corrected − heading_enc|
    max_residual = max(max_residual, residual)

// 3. Report
Serial: drift_rate, max_residual, final_pos_error
Arduino/C++ code (sensor test)