johan_u

SUTD Competitive Robotics Team · SOAR · VEX U

Thirty seconds you cannot touch

A VEX U match opens with an autonomous period. No driver, no controller, no second chances — the robot does whatever you told it to do weeks ago, in front of everyone. Everything worth learning on this team happens in the space between what you meant to tell it and what you actually did.

Oct 2025joined, and still on the team
3robots, each with its own camera calibration
Both bencheshardware to April 2026, software since

01 · The game

What the format actually demands

Two competitions in one, and they reward opposite things.

Head to head

Thirty seconds of autonomy, then sixty seconds of driver control with match loading allowed. The autonomous period is where matches are quietly decided: it runs blind, against an opponent doing the same, and a routine that works on a clean field at midnight can fail on a scuffed one at nine in the morning.

Skills

Separately there is a skills format — sixty seconds of autonomous coding with no driver, sixty seconds of driving, three attempts each, added together and posted to a worldwide leaderboard. You have to clock the score at a real event. It is the part of VEX that rewards patience rather than tactics, because you are competing against a number rather than a person.

Why it matters to how we build

Driver control forgives a robot that is slightly wrong; you correct it with your thumbs. Autonomy forgives nothing, so the autonomous requirement quietly sets the engineering standard for the whole machine — the drivetrain has to be repeatable, the intake has to know whether it has actually taken something in, and the camera has to know where it is looking.

Briefing slide setting out the VEX U gameplay format: autonomous period, driver control and skills runs
The format, as briefed to the team.
Field layout and route planning on a laptop screen
Planning routes across the field before writing any of them down.

02 · Hardware · Oct 2025 – Apr 2026

The bench half

Protective casing for the brain, pneumatics, motor assembly and sheet metal — the first seven months, and the longer half of my time on this team.

The brain casing

I built the protective casing for the robot brain — the controller that holds the program and every port going to a motor or a sensor. It is the single component you cannot afford to have knocked loose in a collision, and on a machine that spends its life being rammed by another machine, collisions are the design load rather than the exception. A casing that merely holds the brain in place under gravity is not a casing; it is a shelf. The question is what the mounting does on the third impact, not the first.

The failure it prevents is also the one hardest to diagnose afterwards. A port shaken loose mid-match does not announce itself — the robot simply stops doing one thing, the log looks fine, and whoever wrote that subsystem spends the evening reading code that was never wrong.

Pneumatics

Air is stored, regulated, and released through solenoid valves into cylinders — a regulator and gauge setting the working pressure, push-fit fittings and tubing carrying it out to each actuator. What pneumatics taught me is that the interesting failure mode is gradual rather than sudden. A fitting that leaks slightly does not stop the robot; it quietly lowers the pressure available later in the match, so the mechanism that worked in testing becomes the mechanism that is weak in the final thirty seconds. You cannot debug that by watching one run.

Motors, sheet metal and the frame

Motor assembly and sheet-metal fabrication for the structure around it, plus wiring looms and a brain with more ports than you want to trace at eleven at night. Frame work is where tolerance stops being an abstraction: a bracket that is two millimetres out is invisible on the bench and becomes a drivetrain that pulls to one side over three metres of field.

What I took away

Hardware sets the ceiling on what the software can promise. An autonomous routine that assumes the robot travels straight is only as true as the drivetrain underneath it, and no amount of tuning in code will rescue a frame that flexes or a cylinder that is down to half its pressure. Seven months on this bench before I wrote a line of the autonomous code is the reason I stopped treating a failed run as a software bug by default — and the reason the software section below is written the way it is. I did not arrive at the code from the code.

Close view of the robot mechanism with pneumatic cylinders and linkages
The mechanism, up close.
Pneumatic cylinders, wiring and components laid out on a table
Everything laid out before it goes back on.
Assembling the robot by hand with a power drill
Build night.
The VEX robot brain showing its port layout on screen
The brain, and every port that has to stay put.

03 · Software · Apr 2026 – present

Telling it what to do when nobody is holding the controller

Controller movement routines, autonomous run programming, and annotating runs for the camera.

What the routine has to do

Our autonomous code branches on alliance colour, then goes looking for the right blocks by detection class — red if we are red, blue if we are blue — before driving a measured path and taking them in. Motion runs on PROS with LemLib underneath, so a move is expressed as a pose and a target point rather than a guess at how long to run a motor.

The part I like

The intake does not have a sensor telling it whether a block went in. It has current draw. When the motor is loaded, it pulls more; when the block is seated, the draw falls away again. So the routine watches the current, waits out the first few hundred milliseconds of noise, and treats a sustained drop as confirmation. It is a sensor made out of something the motor was already telling us.

What I took away

You are usually one measurement richer than you think. Before adding a part to detect something, it is worth asking what the parts already fitted are quietly reporting — a motor that reports its own current is, for one job, a perfectly good sensor that costs nothing and cannot fall off.

Autonomous routine source code on screen, branching on alliance colour and reading intake motor current draw
The autonomous routine: alliance branching, a measured move, and current draw standing in for a sensor.
The team working on the robot at tables with laptops
Most of it happens like this.

04 · The rework

Three robots, three sets of eyes

Reworking the camera-calibration pathways, and backing the files up.

The problem

A camera does not see straight. Every lens distorts, and every camera is mounted at a slightly different height and angle, so before vision is worth anything you have to measure two things: how the lens bends the image, and how a point on the floor maps to a point in the frame. You measure both by photographing a checkerboard, carefully, many times.

We run three robots. Each needs its own calibration, and some need more than one — a mapping for the ground plane and another for when the camera toggles position. Which meant a folder of files where the wrong one loading silently is worse than none loading at all, because the robot keeps driving and simply believes something false.

What I changed

I reworked the file pathways so each robot resolves to its own calibration explicitly, and I put the calibration files into backup. That second half sounds trivial. It is the half that matters: a calibration takes an afternoon with a checkerboard to produce and a careless moment to lose.

The calibration tree

camera_calibration/
├── camera_calibration.py    # shoot the checkerboard
├── camera_check.py          # verify a calibration
├── config.yml
├── Calibration Checkerboard.png
├── Hehe_robot/
│   └── camera_distortion_calibration.yml
├── huang_robot/
│   ├── camera_ground_homography_calibration.yml
│   └── camera_toggle_homography_calibration.yml
└── jetson_robot/
    ├── camera_ground_homography_calibration.yml
    └── camera_toggle_homography_calibration.yml

That term's log

  • 22 May
    Camera calibration. The pathway rework and the backups.
  • 29 May
    Override template. A clean clone, a first attempt at mains, then a new template.
  • 3 June
    Updated main. Template and entry point brought back together.
  • 4 June
    New robot move. Motion primitive rewritten.
  • 5 June
    Full override testing. End to end, on the field.

What I took away

The Trials/ folder on that team still holds two archives, named Working and Not Working. Keeping the second one is the habit worth having: a calibration that failed tells you which measurement was wrong, and deleting it means the next person re-runs the same afternoon to learn the same thing. A silently wrong file is the dangerous case — the robot keeps driving and simply believes something false — so the rework was as much about naming and backing up the files as it was about the maths.

PROSLemLibC++ PythonOpenCV calibrationHomography

Elsewhere on this site

The rest of it

The orchestra, the fortnight in Bali, the clubs that outlived me, and the competition record — including the team award this season — all sit together on one page.