Desk robot / Calculus / StormHacks 2026 SFU Burnaby · Oct 3–4

Otter Tutor

It sees your mistake. It won't tell you the answer.

A desk robot that watches you solve calculus on a whiteboard, points a laser at the line where it went wrong, and lets you fix it yourself.

Otter screen · 240×320, portrait

Hmm, take another look at which rule you picked when you took the derivative on line 2.

d/dx [x² sin x] =
2x sin x − x² cos xsin² x Line 2 · wrong_rule · first nudge
01 / Hardware

Real hardware. Built overnight.

Fig. 1 · The CAD, 360° turntable Two servos, one laser, seven printed parts. The arm pans and tilts to land on any line of the board.
The finished yellow Otter Tutor robot seen from the front, clipped onto a webcam on a tripod, with the otter's face on its screen and the laser arm on the right.
Fig. 2 · Photo, the real one Printed in yellow, otter on the screen, laser arm on the right, clipped onto the 2K webcam.

Spec sheet

Otter Tutor hardware specifications
Display2.8" ILI9341 · 240×320, portrait
Moods6: idle, listening, thinking, talking, happy, confused
Arm2× SG90 · pan ±60°, tilt −40° to +15°, eased at up to 150°/s
PointerRed laser. Aims first, then lights for 4 s. The firmware cuts it at 6 s.
Eyes2K USB webcam, read at 1920×1080
EarsThe laptop's own mic, tap to talk. Never the webcam mic.
VoiceElevenLabs on the laptop speakers, lip-synced on the screen
BrainLaptop (Python, FastAPI). The ESP32 joins it over a Wi-Fi WebSocket.
If the link dropsLaser off, head back to center, face to idle
7 printed parts that clip onto the webcam
02 / Circuit

How it's wired.

One ESP32 runs everything on the robot: two servos, the laser and the screen. Point at a number to see its pins.

Fig. 3 · Wiring diagram

Wiring diagram: an ESP32 DevKit on a breadboard wired to a pan servo, a tilt servo, a KY-008 laser module switched through an NPN transistor with a 1 kilo-ohm resistor, a 470 microfarad capacitor, and a 2.8 inch ILI9341 screen.
The back of the robot opened up: the ESP32 on a small breadboard inside the yellow case, with jumper wires running to the servos and the laser arm.
Fig. 4 · Photo, inside the case The same circuit, packed into the case.

Pin map, from our firmware

Which ESP32 pin each part uses
#PartESP32 pinWhat it does
1ESP32 DevKit—Runs the face, servos and laser. Joins the laptop over Wi-Fi.
2Pan servo (SG90)GPIO 25Turns the head ±60° left and right.
3Tilt servo (SG90)GPIO 26Tilts from −40° to +15°, so the laser stays below eye level.
4Laser (KY-008), NPN, 1 kΩGPIO 27The pointer. The firmware turns it off after 6 s.
52.8" ILI9341 screenMOSI 23 · SCLK 18 · MISO 19 · CS 5 · DC 16 · RST 17The otter's face, over SPI, portrait 240×320.
6470 µF capacitorPower railSits across the breadboard's power rail.

The diagram shows the transistor version from our wiring guide. On the final robot the laser runs straight from GPIO 27, active-low.

03 / The problem

It's 1 a.m. Line 3 is wrong. You can't see why.

So you snap a photo, an app hands you the full solution, and you copy it down. It feels like progress. Then the quiz shows up, and there's no app on the quiz.

Getting the answer isn't the same as finding it.

Photo solvers

Answer in two seconds. Learning in zero.

Chatbots

Ask for a hint, get the whole solution.

Answer keys

They tell you that it's wrong, not where.

04 / Demo

Your turn. Pick a line 2.

Find d/dx [x² · sin x]. Choose what you'd write next.

d/dx [x² · sin x] =
your line 2 appears here
Otter screen · live

Watching the board…

Choose your line 2

What the otter did

Waiting for your line 2
What the otter did with your line 2
VerdictPick a line 2 above
First nudgeNothing yet
Second hint
Only if you keep going with the mistake
It didNothing yet
It knew, but didn't say
Hidden. Press Reveal to see it.

Built from the robot's real templates. Notice what it never says. Confidence values are examples, and the wait is shortened: a real check takes a few seconds while Gemini reads the board.

05 / How it decides

Quiet until it's sure.

  1. Step 1

    It watches. A 2K webcam films the board. OpenCV, in C++, finds the whiteboard, flattens it to a straight-on view and makes the ink stand out.

  2. Step 2

    It waits. A check starts only when something new is on the board and nothing has moved for 5 s. At most one check every 5 s.

  3. Step 3

    Gemini reads every line. Each line becomes LaTeX with a verdict: ok, wrong rule, misapplied, arithmetic or unclear. It boxes the first wrong line. If one model is unsure, the next one is asked.

  4. Step 4

    SymPy re-checks the math. If it can parse the flagged line and finds it's actually correct, the flag is dropped.

  5. Step 5

    The policy decides. It speaks only at confidence 0.70 or higher, once per mistake, at most every 20 s. Half-written lines and unclear ones are never spoken about.

  6. Step 6

    It points and speaks. The box becomes pan and tilt through 4 calibrated corners. The laser aims, then lights for 4 s, while ElevenLabs says the nudge and the otter's mouth follows the audio.

Level 1 · First nudge

What you were doing, and the line.

“Check how you took the derivative on line 1.”

Level 2 · Second hint, once

The exact part of the line. Only if you ask again, keep writing with the mistake still there, or nothing on the board moves for 60 s. Then it stays quiet about that mistake.

“Look at what happened to the x when you took the derivative on line 1.”

Never

The rule's name, the method, a corrected step, or the answer. A word filter checks every line before it's spoken. If a line fails, a safe fixed sentence replaces it.

Talk to it

Tap to talk on the laptop's mic. It listens until you pause for about a second, ElevenLabs transcribes you, and Gemini answers while looking at the board. Small talk and concepts in plain words are fine. Ask about your mistake and it answers by the same rules, with the laser on that line.

System status

Otter Tutor system status
Confidence to speak0.70
Board still before a check5 s
Between spoken nudges20 s
Second hint if nothing moves60 s
Laser on per flag4 s
Laser safety cut-off6 s
Answers given0

Rules it lives by

  • Name the line, never the fix.
  • One nudge, one hint, then quiet.
  • A false alarm is worse than a miss.
  • The laser stays below eye level.
06 / Final setup

From breadboard to tripod.

  1. Step 1 · Breadboard
    The screen wired on a breadboard, showing the otter in inverted colors, with servos, a laser and a laptop around it.

    First boot. The colors came out inverted.

  2. Step 2 · Printed case
    A hand holding the yellow 3D-printed case with otter ears, the screen inside showing the golden otter.

    The first printed case, ears included.

  3. Step 3 · Tripod
    The finished robot clipped onto a webcam on a tripod, held up for a test while a teammate checks it from his phone.

    First full test on the tripod.

07 / Built in 24 hours

What broke, and what we did about it.

Quota

20req / day

Gemini's free tier gave us 20 requests a day. We built key rotation, model fallbacks, and a cached demo run.

Arm

0collisions

The first arm swung straight into its own body. We tested every angle in CAD until nothing collided.

False alarms

1veto

The AI sometimes flagged correct work. Now a math engine has veto power.

Stack

  • Gemini API
  • ElevenLabs
  • OpenCV (C++)
  • SymPy
  • Python + FastAPI
  • ESP32
  • WebSocket
  • Bambu Lab printing
  • Chris

    The brain

    Gemini vision, the SymPy check, the nudge policy and the laptop server.

  • Sebas

    CAD + printed body

    Designed and printed the body and the arm, and wired a lot of the electronics.

  • Leandro

    Hardware

    Electronics, wiring and firmware.

  • Allen

    Hardware

    Electronics, wiring and firmware.