Skip to content

feat Aruco/Apriltag generator - #2037

Merged
leshy merged 11 commits into
mainfrom
apriltag-generator
May 12, 2026
Merged

leshy merged 11 commits into
mainfrom
apriltag-generator

Conversation

@leshy

@leshy leshy commented May 9, 2026 •

Copy link
Copy Markdown
Member

Problem

I wanted a nice PDF generator for april tags, quickly vibed.
Size ruler for validation, intelligent packing

getting ready for #2036

Solution

2026-05-09_22-08 2026-05-09_22-07

How to Test

dimos apriltag --help

example outputs

tags_50.pdf

tags_75.pdf

Contributor License Agreement

  • I have read and approved the CLA.

Comment thread dimos/utils/cli/apriltag.py
Comment thread dimos/utils/cli/apriltag.py Outdated
@leshy leshy added the PlzReview label May 9, 2026
@dimensionalOS dimensionalOS deleted a comment from greptile-apps Bot May 9, 2026
@greptile-apps

greptile-apps Bot commented May 9, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds a new dimos apriltag CLI command that generates printable AprilTag/ArUco PDFs with a calibration ruler, supporting all standard tag families, configurable page sizes, and a grid packing mode.

  • dimos/utils/cli/apriltag.py: new vector-PDF renderer using ReportLab; draws tag cells as merged rect runs to avoid hairline artefacts, with optional grid packing and centering logic.
  • dimos/robot/cli/dimos.py: thin Typer command that lazily imports the generator, preserving startup performance when the apriltag extra is absent.
  • pyproject.toml / uv.lock: new apriltag extra (opencv-contrib-python==4.10.0.84, reportlab>=4.5.0) correctly replaces the previously flagged pupil-apriltags dependency.

Confidence Score: 4/5

Safe to merge after adding upfront ID-range validation in generate_pdf.

The generator opens the output file via canvas.Canvas before any per-ID bounds check runs. An out-of-range ID raises mid-render, bypasses c.save(), and leaves a created-but-empty file at out_path with no cleanup. The fix is a single pre-flight loop before the Canvas constructor, consistent with the other validations already present.

dimos/utils/cli/apriltag.py — specifically generate_pdf, which needs per-ID bounds validation before Canvas construction.

Important Files Changed

Filename Overview
dimos/utils/cli/apriltag.py New PDF generator for AprilTag/ArUco markers. Core rendering logic is sound, but generate_pdf opens the output file via Canvas before validating individual IDs, meaning an out-of-range ID raises mid-render and leaves a corrupt file behind.
dimos/utils/cli/test_apriltag.py Good coverage of parse_id_spec, grid layout, PDF generation modes, and family variants; no test for the out-of-range ID mid-render scenario.
dimos/robot/cli/dimos.py New apriltag Typer command wires CLI options to generate_pdf; lazy import avoids startup overhead when the extra is absent.
pyproject.toml New apriltag extra correctly declares opencv-contrib-python==4.10.0.84 and reportlab>=4.5.0; types-reportlab added to dev.
.gitignore Adds /apriltags.pdf (default output path) to .gitignore.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    CLI["dimos apriltag CLI\n(dimos.py)"] -->|"parse_id_spec(ids)"| PARSE["ID list\n[0, 1, 2, ...]"]
    PARSE --> GEN["generate_pdf()"]
    GEN -->|validate family/page/size| VAL{Valid?}
    VAL -->|No| ERR1[raise ValueError]
    VAL -->|Yes| CANVAS["canvas.Canvas(out_path)"]
    CANVAS -->|pack=False| SINGLE["_draw_single_page()\nper tag"]
    CANVAS -->|pack=True| LAYOUT["_grid_layout()\ncols x rows"]
    LAYOUT --> PACKED["_draw_packed_page()\nper batch"]
    SINGLE --> TAG["_draw_tag()\n→ _cell_matrix()\n→ cv2.aruco.generateImageMarker"]
    PACKED --> TAG
    SINGLE --> RULER["_draw_ruler()"]
    PACKED --> RULER
    TAG --> SAVE["c.save() → PDF"]
    RULER --> SAVE
Loading

Comments Outside Diff (1)

  1. dimos/utils/cli/apriltag.py, line 330-337 (link)

    P1 Missing upfront ID range validation

    generate_pdf validates family, page size, and geometry before opening the output file, but never checks whether each ID is within the chosen family's valid range. The per-ID guard lives in _cell_matrix (line 157) and raises ValueError mid-render, after canvas.Canvas(str(out_path), ...) has already created the file. The exception bypasses c.save(), leaving an empty/corrupt file at out_path. For example, dimos apriltag --ids 0-600 with --family tag36h11 (max 586) silently creates a zero-byte PDF and exits with a traceback.

    Adding a pre-flight check like if any(i < 0 or i > max_id for i in ids): raise ValueError(...) before line 352 would be consistent with the other validations that precede Canvas construction.

Reviews (6): Last reviewed commit: "Merge branch 'main' into apriltag-genera..." | Re-trigger Greptile

leshy added 2 commits May 9, 2026 22:30
Switch from mypy-ignore to types-reportlab>=4.5.0 (matches reportlab 4.5
in deps), matching the project's pattern for the other ~15 types-* packages.
The stubs immediately caught a real bug — Canvas.setKeywords expects str |
None, not list[str].
@codecov

codecov Bot commented May 9, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.54839% with 14 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
dimos/utils/cli/apriltag.py 93.33% 5 Missing and 5 partials ⚠️
dimos/robot/cli/dimos.py 33.33% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@mustafab0 mustafab0 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this to be a cli utility?

Can be just a regular utility function/script. Wouldn't hurt to have it but also use cases seem not as frequent to warrant a cli tool.

Comment thread dimos/utils/cli/apriltag.py
@mustafab0

Copy link
Copy Markdown
Contributor

Also, we should add support for ArucoTags (a separate family) and also very widely used.

@leshy

leshy commented May 10, 2026

Copy link
Copy Markdown
Member Author

Do we need this to be a cli utility?

Can be just a regular utility function/script. Wouldn't hurt to have it but also use cases seem not as frequent to warrant a cli tool.

good point, I kinda like that dimos something can quickly access all tooling we have, but it's a bit stupid to modify a single cli entrypoint file for this, I think maybe dimos something should just delegate to some tool/something.py dir of individual scripts

let us think about it, and let me merge this for now

@leshy leshy changed the title feat Apriltag generator feat Aruco/Apriltag generator May 10, 2026
@leshy

leshy commented May 10, 2026

Copy link
Copy Markdown
Member Author

Also, we should add support for ArucoTags (a separate family) and also very widely used.

added

@leshy
leshy enabled auto-merge (squash) May 12, 2026 02:54
@mustafab0

Copy link
Copy Markdown
Contributor

--pack argument not working for me. I can only get 1 aruco/April tag on one page.

I run the following dimos apriltag --ids 4 --pack 5

Attached is the output
apriltags.pdf

@leshy

leshy commented May 12, 2026 •

Copy link
Copy Markdown
Member Author

dimos apriltag --ids 4 --pack 5

you selected only id 4 with this command

dimos apriltag --ids 4-10 --pack

also pack is default so you don't need to include it

dimos apriltag --help

@leshy
leshy merged commit bc0fd67 into main May 12, 2026
10 of 12 checks passed
@leshy
leshy deleted the apriltag-generator branch May 12, 2026 19:45
mustafab0 pushed a commit that referenced this pull request May 13, 2026
jiangtao129 added a commit to jiangtao129/dimos that referenced this pull request May 14, 2026
* perf(rerun): render voxel maps as Points3D spheres instead of Boxes3D (dimensionalOS#1793)

* feat(api): add porcelain api with connect (dimensionalOS#1779)

* fix(rerun): dimos-viewer version upgrade (dimensionalOS#1785)

* Task: Add meaningful manipulation tests (dimensionalOS#1765)

* feat: never leave child processes alive after the parent (dimensionalOS#1886)

* Fix mac UDP (dimensionalOS#1789)

* Remove sim from base install (dimensionalOS#1878)

* fix(tests): fix flakey porcelain test (dimensionalOS#1900)

* feat(go2): rage mode via webrtc (dimensionalOS#1903)

* feat:rust native modules (dimensionalOS#1794)

Co-authored-by: leshy <lesh@sysphere.org>

* Feat/memory2 - plotting, examples, recorder module, semantic search (dimensionalOS#1769)

Co-authored-by: RD <63036454+ruthwikdasyam@users.noreply.github.com>

* fix attributes (dimensionalOS#1918)

* Jeff/fix/rconnect2 (dimensionalOS#1784)

* fix(types): resolve mypy 3.10 errors (dimensionalOS#1921)

* feat(go2):  go2 SDK adapter + nix cyclonedds setup (dimensionalOS#1885)

Co-authored-by: Mustafa Bhadsorawala <39084056+mustafab0@users.noreply.github.com>

* Revert "Jeff/fix/rconnect2" (dimensionalOS#1924)

* feat(modules): async modules (dimensionalOS#1920)

* chore(logging): enforce usage of setup_logger (dimensionalOS#1895)

* feat(api): peek_stream (dimensionalOS#1909)

* CI/macos: skip failing tests (dimensionalOS#1944)

* fix(ci): restrict code-cleanup workflow to Linux runners only (dimensionalOS#1948)

* Fix/memory2 go2 autorecorder (dimensionalOS#1925)

* Convert patrol module to be an async module (dimensionalOS#1939)

* feat(tool-streams): add tool streams (dimensionalOS#1713)

* G1 Low level connection module coordinator integration (dimensionalOS#1954)

* feat(sim): MuJoCo sim teleop for xarm + piper (dimensionalOS#1958)

* Show child process cpu usage in dtop (dimensionalOS#1880)

Co-authored-by: leshy <lesh@sysphere.org>

* Task: OpenArm Integration with DimOS (dimensionalOS#1897)

Co-authored-by: Paul Nechifor <paul@nechifor.net>
Co-authored-by: RD <63036454+ruthwikdasyam@users.noreply.github.com>
Co-authored-by: Andrew Lauer <69774903+aclauer@users.noreply.github.com>
Co-authored-by: leshy <lesh@sysphere.org>
Co-authored-by: Jeff Hykin <jeff.hykin@gmail.com>

* md-babel-py bump (dimensionalOS#1994)

* new hong kong office recording (dimensionalOS#1991)

* chore(security): update packages with issues (dimensionalOS#1989)

* Make whisper an optional extra with faster-whisper by default (dimensionalOS#1877)

* Drop perception. Update docs. (dimensionalOS#1888)

* Add codecov (dimensionalOS#1889)

* go2 lidar timestamps bugfix (dimensionalOS#1992)

* go2 cli (dimensionalOS#1990)

* refactor(core): memory2 for dtop (dimensionalOS#2004)

* fix: adaptive timestamp correction (dimensionalOS#2021)

Co-authored-by: Ivan Nikolic <lesh@sysphere.org>

* Disable codecov status check (dimensionalOS#2026)

* fixes replay mem leak (dimensionalOS#2025)

* fix: launch arm blueprints with --simulation flag (dimensionalOS#2027)

* small fixes for release (dimensionalOS#2019)

* chore: add problems back

* Change Codecov branch from 'dev' to 'main'

* docs: remove mentions of dev

* Ivan/fix/go2recording2 (dimensionalOS#2034)

* mapper memory leak fix, measurement transforms (dimensionalOS#2031)

* Feat/1759 doc codeblocks ci (dimensionalOS#1884)

* Nav Stack 0.1

* fix(security): upgrade some packages (dimensionalOS#2040)

* go2 apriltag recordings (dimensionalOS#2044)

* Ivan/fix/doc codeblocks added skip2 (dimensionalOS#2052)

* feat Aruco/Apriltag generator (dimensionalOS#2037)

* Split tests off of self hosted runner (dimensionalOS#1901)

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix(verify): exclude unitree-dds extra to avoid cyclonedds C lib

Upstream introduced `dimos[unitree-dds]` which depends on
`cyclonedds==0.10.5`. The Python binding tries to compile against the
CycloneDDS C library, which is not installed on the fork's
ubuntu-latest runner. This makes verify fail with:
  Could not locate cyclonedds. Try to set CYCLONEDDS_HOME or CMAKE_PREFIX_PATH

Upstream's own `ci.yml` (line 36) already passes
`--no-extra dds --no-extra unitree-dds`; align the fork's verify with it.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: RD <63036454+ruthwikdasyam@users.noreply.github.com>
Co-authored-by: Paul Nechifor <paul@nechifor.net>
Co-authored-by: Mustafa Bhadsorawala <39084056+mustafab0@users.noreply.github.com>
Co-authored-by: Sam Bull <git@sambull.org>
Co-authored-by: Andrew Lauer <69774903+aclauer@users.noreply.github.com>
Co-authored-by: leshy <lesh@sysphere.org>
Co-authored-by: Jeff Hykin <jeff.hykin@gmail.com>
Co-authored-by: stash <pomichterstash@gmail.com>
Co-authored-by: Dan Vi <bogwi@tutamail.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: jiangtao-huazhijian <jiang.tao@topsunpower.cc>
Co-authored-by: Cursor <cursoragent@cursor.com>
jeff-hykin pushed a commit that referenced this pull request Oct 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants