ME 210 · Winter 2026 · Stanford University

Turty Droid

An autonomous puck-shooting robot powered by ultrasonic navigation,
proportional-derivative (PD) wall-following, and encoder-controlled precision firing.

Team Pringle with Turty Droid

01

Bill of Materials


02

State Diagram

The robot operates as a finite state machine. Transitions are driven by ultrasonic sensor readings and timer events.

State diagram showing robot behavior states
Hand-drawn state diagram for Turty Droid

States Overview

State Behavior Transition
Rotate CCW 1 Spin counter-clockwise searching for back wall ≤ 15 cm
Rotate CCW 2 Continue spinning to detect side alignment L + R ≈ 90 cm
Line Following PD-controlled wall following using side sensors ≥ 150 cm
Align & Shoot Fine-tune alignment, then fire 3 pucks 3 shots
Retreating Drive in reverse toward loading zone ≤ 15 cm
Loading Wait 10 seconds for puck reload timer

03

Circuit Diagram

Initial circuit schematic
Initial Design

3 TCRT5000 line sensors + 4 TSDP34356 IR sensors (2 front, 2 back) with MCP6294 op-amp conditioning for orientation.

Final circuit schematic
Final Design

Simplified to 3 HC-SR04 ultrasonic sensors (left, right, rear). Eliminated all analog circuitry for cleaner, more reliable sensing.

Pin Assignments — Final Design

Function Arduino Pin(s)
Left Motor (PWM / IN1 / IN2) 6 / 7 / 8
Right Motor (PWM / IN3 / IN4) 9 / 13 / 12
Shooter Motor (PWM / IN1 / IN2) 16 / 15 / 14
Shooter Encoder (A) 18
Back Ultrasonic (Trig / Echo) 2 / 3
Left Ultrasonic (Trig / Echo) 10 / 11
Right Ultrasonic (Trig / Echo) 4 / 5

04

Calculations

Ultrasonic Distance

Each HC-SR04 measures time-of-flight and converts to centimeters:

distance = (duration × 0.0343) / 2

Speed of sound ≈ 343 m/s = 0.0343 cm/μs. Divide by 2 for round-trip.

PD Wall-Following Control

PD controller on the difference between left and right distances:

error = leftDist − rightDist

leftSpeed = BASE_L − Kp × err − Kd × deriv

rightSpeed = BASE_R + Kp × err + Kd × deriv

Tuned: Kp = 0.7, Kd = 0. Speeds clamped to [0, 160].

Shooter Encoder Positioning

Rotary encoder for precise 90° quarter-turn shots:

PPR = 690COUNTS_90 = 173

Slowdown window of 100 counts linearly ramps PWM from 205 → 15.

Timer1 Interrupt (100 Hz Control Loop)

Timer1 CTC mode, prescaler 64:

OCR1A = 16MHz / 64 / 100Hz − 1 = 2499

Gives a 10 ms control period for the PD loop.

Side-Sum Alignment

Wall alignment detected when L + R sum hits target:

101.3 cm ± 1.5 cm (rotation)

101.3 cm ± 0.5 cm (fine shoot alignment)


05

Code

Full Arduino sketch — finite state machine with interrupt-driven encoder counting and a Timer1-based 100 Hz control loop.

turty_droid.ino
Loading...

06

Team Takeaways

Sensor Filtering Matters

Raw ultrasonic readings were noisy and occasionally returned bogus values (>300 cm). A simple validity check dramatically improved reliability. A running average or median filter would have helped further.

Strobing Solved Our Consistency Problem

Early on, our robot was very inconsistent — ultrasonic readings were unreliable when the robot was moving or facing a wall at a non-perpendicular angle. We fixed this by implementing a "strobe" pattern: the robot drives for 500 ms, then stops for 500 ms to take sensor readings while stationary. This gave the ultrasonics clean, stable measurements and made navigation dramatically more repeatable.

Simplify Your Sensors

Our initial design used 3 line-following sensors, 4 IR sensors with op-amp conditioning, and a servo — way too complex. By stripping it down to just 3 ultrasonic sensors for all navigation, we eliminated most of our analog circuitry and failure points. Fewer sensors meant simpler code, easier debugging, and a more reliable robot.

State Machines Are Your Friend

Structuring code as an FSM made debugging straightforward — we could isolate and test each state independently. Serial logging of state transitions was invaluable.


07

Competition Day

Team Pringle made it to the semis of the ME 210: The Joy of Curling tourney!

Arena map showing the 4-foot by 16-foot curling sheet layout
The arena: a 4' × 16' curling sheet. Each robot starts with 3 pucks, autonomously navigates to a shooting position, and fires at a bullseye target — 5 pts for the center, 2 for the middle ring, 1 for the outer ring. After shooting, the robot returns to its starting zone for a reload. Matches are 2-minute head-to-head rounds.
ME 210 competition bracket showing Team Pringle in semifinals
Tournament bracket — Team Pringle seeded #12, advanced to semis :D
Turtle twerk