Cleaning Up, Pipelining, and Bake-Testing the STM32H750 Tracker

Cleaning Up, Pipelining, and Bake-Testing the STM32H750 Tracker

A sequel to the first STM32H750 tracker post. After the C++ port was proven in production, I spent a week of evenings cutting dead vendor code, splitting the algorithm out to host for unit tests, wiring the LCD SPI through DMA to let the CPU run the tracker in parallel with the blit, unlocking the camera’s real frame rate, chasing a subtle BB-drift bug back to a too-wide SAD search, and finally building an offline A/B harness that compares SAD, NCC, and MOSSE on four synthetic scenarios so the next tracker port is a data decision, not a vibes one.

April 23, 2026 · 18 min · Pavel Guzenfeld
Building a Template-Matching Tracker on an STM32H750

Building a Template-Matching Tracker on an STM32H750: What Worked, What Didn't

A long, honest retrospective on turning a WeAct STM32H750 board, a cheap OV7725 IR camera, and an Xbox controller into a live template-matching tracker. Every dead end, every wrong assumption, every fix — and what I’d do differently next time.

April 21, 2026 · 23 min · Pavel Guzenfeld
Pathfinding algorithms for games — A*, JPS, Theta*, flow fields, visibility graphs

Game Pathfinding Algorithms, Benchmarked: A*, JPS, Theta*, Flow Fields, Visibility Graphs

Five pathfinders implemented in C++23, each in a single Godbolt-ready file, benchmarked on the same grids. A* is the baseline. JPS expands 22x fewer nodes on open maps yet runs slower than A* in naive form. Theta* produces shorter any-angle paths at 2-8x the cost. Flow fields dominate when many agents share a goal. Visibility graphs — AoE II DE’s approach — need 5 waypoints where A* needs 600. Plus the StarCraft ‘harvesters ignore collisions’ hack and why SC2 switched to navmeshes.

April 18, 2026 · 15 min · Pavel Guzenfeld
O3DE multi-camera rendering performance analysis

Chasing 18 Milliseconds: A Performance Deep Dive into O3DE's Render Readback Pipeline

We spent a full session systematically profiling O3DE’s multi-camera streaming pipeline, testing eight different optimization approaches, and pinpointed the exact bottleneck: 18 ms of fixed overhead in the AttachmentReadback scope system. Here’s what we tried, what we measured, and what it means for the engine.

April 17, 2026 · 7 min · Pavel Guzenfeld
Three live Godot camera streams over RTP/UDP rendered by GStreamer clients

From Unity to Godot: Multi-Camera Streaming at 50 FPS with Async GPU Readback

After O3DE’s 18 ms frame-graph readback made 30 FPS streaming impossible, we tried Godot. It got us there — eventually. This is the full path from 105 FPS on nothing to 50 FPS per camera with three live RTP streams, including every wrong turn and every underdocumented Godot behavior we hit on the way.

April 17, 2026 · 12 min · Pavel Guzenfeld
O3DE rendering a ground plane from a camera spawned programmatically inside a headless Docker container

From Unity to O3DE: Multi-Camera Streaming at 1080p in a Headless Docker Container

Exploring whether O3DE can replace Unity as the render engine for a drone simulation that streams multiple 1080p camera feeds via GStreamer. From first scaffold to three live RenderToTexture pipelines in a single session.

April 16, 2026 · 6 min · Pavel Guzenfeld
Six Optiver-Style C++ Problems: Order Books, Dijkstra, DP, and Price Alert Router

Six Optiver-Style C++ Problems: Order Books, Dijkstra, DP, and an AoS→SoA Rewrite

Working through six C++ problems modeled on Optiver’s Senior SWE assessment: supermarket checkout simulation, order book matching, dividend pricing, lattice path DP, Dijkstra with K free edges, and a price-alert router built twice — AoS first, then SoA. Every bug, wrong turn, and data structure tradeoff included.

April 12, 2026 · 18 min · Pavel Guzenfeld
Why You Should Use stableNorm() Instead of norm()

Why You Should Use stableNorm() Instead of norm(): A Lesson from Eigen Code Review

A one-word review comment on my Eigen MR revealed that hand-rolling normalization with .norm() silently breaks on extreme inputs. Eigen already had the fix — I just wasn’t using it.

March 27, 2026 · 5 min · Pavel Guzenfeld
Fixing O(N²) Entity Addition in ROS 2's CallbackGroup

Fixing O(N²) Entity Addition in ROS 2's CallbackGroup

How a simple erase-remove in every add_timer() call turned entity registration into a quadratic bottleneck — and the 71x speedup from moving cleanup to the right place.

March 23, 2026 · 4 min · Pavel Guzenfeld
Upgrading Householder Right-Side: BLAS-2 to BLAS-3

Upgrading Eigen's Householder Right-Side Application from BLAS-2 to BLAS-3

Eigen’s blocked Householder path only existed for left-side application. I added the right-side equivalent, upgrading M*Q from O(n) rank-1 updates to cache-friendly blocked matrix multiplies.

March 23, 2026 · 4 min · Pavel Guzenfeld