quick fiduciary 3d printable generator#3166
Open
leshy wants to merge 11 commits into
Open
Conversation
`dimos apriltag --3d` writes a directory holding, per tag, a base STL, a marker STL, a back-text STL and a 3MF with the colors baked in, alongside the existing PDF. The plate is a rounded rectangle whose side flanges carry four mounting holes; base and marker meet flush at the top face so the printed surface is flat rather than embossed. `--legs H` adds a matching pair of T-footed stands, H measured floor to tag centre, taking their hole spacing from the plate the tag actually generated. Also prints the resolved configuration before generating anything.
leshy
requested review from
mustafab0,
paul-nechifor and
spomichter
as code owners
July 24, 2026 11:30
Contributor
Greptile SummaryAdds a CLI-driven 3D-printable fiducial generator and inverted-marker detection support.
Confidence Score: 4/5The PR should not merge until invalid 3D configurations are rejected before any output files are written. Geometry validation currently occurs after PDF generation, so a failed invocation leaves a partial output set despite reporting a parameter error. dimos/utils/cli/apriltag.py Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart LR
CLI["dimos apriltag"] --> Request["TagRequest"]
Request --> PDF["PDF generator"]
Request --> Mesh["3D mesh generator"]
Mesh --> STL["STL parts"]
Mesh --> MF["Colored 3MF"]
Map["dimos map --marker-inverted"] --> Detector["ArUco detector"]
Detector --> Detections["Fiducial detections"]
Reviews (6): Last reviewed commit: "test(apriltag): stop paying for the back..." | Re-trigger Greptile |
❌ 1 Tests Failed:
View the top 1 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
Review fixes: describing a request indexed its IDs and looked up its family before any error handling, so an empty --ids or an unknown --family produced a traceback rather than a parameter error; and colors went into the 3MF unchecked, so --marker-color red silently wrote an invalid displaycolor. TagRequest now validates on construction and write_3mf validates the color, with the whole CLI flow inside the error boundary. Catches --ids 10-5 too. --frame swaps the mounting holes for a picture frame emitted as its own part, to print in another material: a stepped moulding with a bead run and corner rosettes, and a rabbet the tag drops into. The lip is opaque and a different color, so it takes only what the margin can spare beyond the one-cell quiet zone the detector needs, and is refused outright when there is nothing spare. Back text now fills 90% of the plate rather than 80%, for fatter strokes.
…van/feat/printable_tags
…ults to 2 --frame now takes the band width in mm (15 is the usual) rather than being a flag, and the frame color is fixed rather than exposed. --margin-cells defaults to 2, which is what a frame needs anyway to keep the quiet zone clear of the lip. The frame's top rail carries a recess for hanging it on a nail by a rope. Both the rope and the nail head sit inside it, so the back stays flat against the wall — anything proud of the back holds the frame off the wall, and its mass, which sits in front of the wall plane, then swings it until the centre of mass hangs under the nail. The rope threads under a bar at each end of the recess; each bar bridges a short span so it prints without support, and the recess closes before the face so none of it shows from the front.
The frame's hanging recess now holds two free-standing posts, joined to the frame only at their base so a rope can pass right around each. A rope ties round both and loops over a nail above; a door above each post lets its end out through the top edge, leaving the rail solid between them. Nothing protrudes past the back plane and nothing is cut through to the face, so the frame sits flat on the wall and none of it shows from the front. --margin-cells now defaults to what the build needs rather than a flat 2: the detector wants one light cell around the black border and nothing more, and only a frame needs a second, since its lip laps over the plate edge and must leave that cell still showing. Flanges and legs reach outward and never touch the quiet zone. A bare plate is 62.5 mm rather than 75 mm for a 50 mm tag, 31% less plastic. build_tag_meshes and generate_3d default to one cell to match, which they previously did not.
The frame, its rope hanger and --frame come out so this PR stays about the printable tag itself. Kept on ivan/feat/printable_tags_frame. --margin-cells goes back to a plain default of one cell, which is what the detector wants around the black border; the second cell only ever existed for the frame's lip.
A multicolor 3D print with its two filaments swapped comes out as a photographic negative — dark plate, light tag border — and OpenCV skips it silently. Wire detectInvertedMarker through create_aruco_detector, detect_markers_in_image and DetectMarkers, and expose it as `dimos map --marker-inverted`. Found on a Go2 recording where all 432 frames detected nothing; with the flag 99 detections of tag 0 come out at 0.33 px median reprojection error. Off by default: it costs a little false-positive headroom in cluttered scenes, and the real fix is to print the tag the right way round.
Nobody picks these. The 3MF only needs the two solids to read as different filaments in the slicer, so pin them to module constants and delete --base-color / --marker-color / --text-color along with the hex validation and the colours row they existed to feed.
The mesh tests ran 11.4s for a print-file generator. Nearly all of it was the back-text raster: build_tag_meshes is 3.09s with it and 0.16s without, and it gets built twice per tag (pocket cut, then inlay). Nothing that checks plate geometry needs an engraving, so nothing here asks for one; text_solid keeps its own coverage via a single glyph. Also swaps trimesh's contains() — the only thing pulling rtree in — for a probe cube intersected with the mesh, which the boolean engine already present answers in one call. Verified identical on all 64 tag cells, and the suite passes with rtree blocked from import. 11.42s -> 1.03s, and pyproject/uv.lock go back to no rtree.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
quick fiduciary 3d printable generator, I don't have a paper printer :D
dimos apriltag --3d --ids 0 --legs 250 --size-mm 75