claudeDroneteam-docs
documentation · reference
Docs reference

Structured knowledge from collected_doc_media/claudedrone_docs/. Browse the tree on the left; the source of truth is markdown in the repo.

28 — Closing the ActiveMapping v1 Sprint in Simulation

How we closed the ActiveMapping v1 sprint: fixed heading drift, killed zigzag tracks, and cut mission completion from 382 steps to 47 in SITL.

stablesimulationupdated 2026-06-16T00:00:00.000ZClaudeDroneSimulationDevLog

What this is: A simulation-team dev-log marking the close of the ActiveMapping v1 sprint — the round of work where a drone learns to map a room by parking at smart vantage points and looking around, instead of flying over every square of floor.

Why it’s here: It’s the honest engineering record of the bugs we hunted (a slowly turning nose, a wandering “zigzag” flight path) and the numbers we landed on once they were fixed. If you ever wonder what “good enough to hand back to the RL team” actually looks like, this is one concrete example.

Date: 2026-06-07 Ticket: ActiveMapping v1 sprint close


Glossary

A few terms show up constantly below. Here they are in plain English with a mental picture for each.

  • ActiveMapping v1 — the first working version of “active” mapping. Passive mapping means you fly everywhere and record what you bump into. Active mapping means the drone reasons about where to stand so its sensors see the most room with the least flying. Picture someone walking into a dark room, taking three steps to the right corner, and sweeping a flashlight — versus pacing every floor tile. We want the flashlight strategy.
  • Sprint close — the moment a chunk of focused work is declared finished. We don’t call a sprint closed because we ran out of time; we close it when the open problems are fixed and the numbers stop moving in the wrong direction.
  • SITL (Software-In-The-Loop) — the real flight-control software (ArduPilot) running on a laptop instead of on a physical flight controller. The autopilot genuinely thinks it’s flying; it just talks to a simulated world instead of real motors. This lets us crash a thousand times for free.
  • Gazebo — the 3D physics simulator that plays the part of “the world.” It draws the room, the walls, gravity, and the way the drone’s sensors would actually bounce off surfaces. SITL handles the brain; Gazebo handles the body and the environment.
  • mavros / ROS2 (Jazzy) — the plumbing. ROS2 (we use the Jazzy release) is the messaging system that lets our code, the autopilot, and the sensors all talk. mavros is the specific translator that converts ROS2 messages into the autopilot’s native language and back.
  • Heading drift — the drone’s nose slowly rotating away from where it should point, like a shopping cart that pulls left. Small per-step, but it compounds.
  • Frontier detection — the technique of spotting the edge between mapped and unmapped space and treating that edge as “go look there next.” It’s how the drone decides the room isn’t fully explored yet.

1. What we wanted

The goal of the sprint was to take a mapping policy that had been trained in the lightweight RL environment and make it actually fly the same way inside the full simulator — SITL plus Gazebo, with real ROS2 messages flowing through mavros. “Same way” is the hard part. In a clean grid-world environment the agent moves in tidy one-cell steps; in the physics simulator the drone has momentum, the nose can drift, and the autopilot’s own flight smoothing can turn a crisp move into a slow crawl.

When the sprint opened, we had a stack of concrete problems:

  • Model transfer. The newer mapping model expects a 21-value observation plus an action mask. We needed the ROS2 wiring to feed it exactly that, every step, with the mask matching reality.
  • Heading drift. We were commanding turns as a rate (“rotate at this speed”) in open-loop fashion. Over many steps the nose wandered off the grid the environment assumed.
  • A safety-margin mismatch. The environment stopped the drone one cell away from a wall; the simulator was stopping it 0.5–0.7 m short. The drone was behaving more cautiously in sim than the policy expected — a classic out-of-distribution gap, where the real situation drifts outside what the policy saw during training.
  • A crawling autopilot. A particular autopilot option made the guided-mode position stream behave like an S-curve, so every move turned into a slow creep instead of a clean translation.
  • Stale parameter names. Our indoor parameter file referenced metric names that a newer ArduPilot development build had renamed, so some settings were silently dead.

2. What we did

We worked through them one bug at a time. The most visible wins:

  • Joint parity. We got the simulator and the environment to replay the same scenario identically — 44 of 44 steps bit-for-bit. That parity is what lets us trust that a fix in one place means the same thing in the other.
  • Observation + mask wiring. The ROS2 layer now hands the model its full 21-value observation together with a matching action mask, validated end to end.
  • Closed-loop absolute yaw. This was the fix that killed heading drift. Instead of commanding a turn rate and hoping, we command an absolute heading and let the loop correct error every step. For the two turning actions specifically, the nose now snaps to the intended angle and stays there. Imagine the difference between nudging a steering wheel and hoping you end up straight, versus a self-parking car that knows exactly which way it should point and holds it.
  • Killing the crawl. We turned off the offending autopilot option and audited the indoor parameter file against the current ArduPilot build, replacing the dead metric names.
  • Floor/margin buffer. The wall-stop logic had two thresholds fighting each other — a “margin” distance and a “floor” distance landing on the same value, producing a tug-of-war right at the wall. We separated them with a buffer so the drone makes a clean decision instead of dithering.
  • snap90. We snapped travel to clean axis-aligned directions. This is the change that made the wandering “zigzag” flight path vanish completely — tracks went from a ragged fir-tree shape to straight lines down the axes.
  • dual-map. We split the map the drone acts on from the map it reports finished on, declaring the mission done against a display map at 92% coverage. This avoids the trap of chasing the last few noisy cells forever.
  • Faster cruise. With the path now clean and the heading stable, we could raise travel speed from 0.30 m/s to 0.50 m/s and still record zero timeouts, zero safety-guard trips, zero crashes, and zero stalls.
  • Per-world geometry + sensor namespace fix. We pinned each test world’s geometry to its actual SDF model (so a 16×10 indoor room is genuinely 16×10), and we fixed a naming issue on the distance-sensor topics so every range channel was verified publishing and subscribing correctly.

3. Results

Here are the final numbers from the empty 6×6 world with snap90, dual-map, and the faster cruise speed all in place, compared against the earlier open-loop run.

Metric v1.5c open-loop (run A) final
MISSION COMPLETE @ step 382 47
stall kicks 238 0
d15 mean (heading error) 5.2° 0.70° (ratio 0.954)
FAST speed (m/s) 0.30 0.50
arrival timeouts / guard / crash — 0 / 0 / 0
track shape fir-tree / zigzag clean axis-aligned straight lines

The headline is the step count: a completed mapping mission dropped from 382 steps to 47. And it isn’t a hollow win — 238 stall recoveries became zero, heading error fell from over five degrees to under one, and the flight path straightened out entirely.

It’s worth being clear about what “mission complete at step 47” means semantically. The drone builds 92% of the map with its sensors — a TF-Luna ranging out to 6.4 m — from a few optimal points near the walls. It is not physically flying over every cell. That’s a deliberate decision: full coverage-path-planning is a different problem and not this sprint’s job. In an empty 6×6 room, two well-chosen positions near the walls see almost the whole space. On real hardware, shadow zones behind furniture will naturally force more exploration through frontier detection — the unmapped edges behind a couch become the next places to go look.

We also confirmed, for the RL team, the actual safety-margin constants from the code so the two systems can be aligned. The summary: the simulator keeps the drone at least as far from walls as the environment expects (and usually a touch farther), which is the safe direction for the mismatch to go — the drone in the environment will never end up closer to a wall than it would in sim.

4. Sources

  • Final tracks and maps in drone_media/sim/tracks/: track_final, map_final, track_yawfix, and the two drift comparison runs.
  • Run videos: sim_20260607_212419.mp4, sim_20260607_210332.mp4, sim_20260607_184232.mp4, sim_20260607_182846.mp4.
  • Companion dev-logs 26 and 27 in this series.

5. What’s next

A few threads stayed open and got handed forward:

  • Margin alignment. The small wall-stop difference between the environment and the simulator is the remaining out-of-distribution gap. The RL side will retrain against the agreed-on stricter margin to close it.
  • Minimum frontier cluster size. We want to ignore tiny single-cell frontiers and only chase clusters of a few cells; the display map already does most of this filtering.
  • World standardization. Wall heights and the indoor room layout need to settle into one shared standard so every test starts from the same physical assumptions.
  • Sensor-namespace documentation. The distance-sensor naming fix is documented, and the full sensor-to-autopilot smoke test will run on the next integration stack.

If you take one thing from this entry: most of the gain here didn’t come from a cleverer model. It came from making the simulated body behave predictably — a steady nose, straight tracks, and a wall-margin that means the same thing on both sides of the fence.

© 2026 claudeDrone Team · auto-pipeline · Nuxt 3 SSR