michaelgale / cq-gridfinity

A python library to build parameterized gridfinity compatible objects such a baseplates and boxes.
MIT License
91 stars 6 forks source link

RuggedBox baseplate dimensions appear to be incorrect? #6

Closed ndevenish closed 8 months ago

ndevenish commented 8 months ago

Standard sized bins don't fit. The overall spacing/dimensions match, but the shape of the base edges appears to be wrong.

Here I've imported the STEP into Fusion360, as compared to one of the bins generated by it's gridfinity plugin image

Measuring the generated geometry: image vs the spec: image

michaelgale commented 8 months ago

I'm not sure what you are seeing in terms of the generated rugged box geometry. If I generate a rugged box and place a gridfinity box in place--it seems to conform?

ruggedbox
michaelgale commented 8 months ago

@ndevenish Perhaps your cross-section view intersects a corner radius which would exaggerate the projected profile?

ndevenish commented 8 months ago

No, it's not cut on a corner. Did you try a gridfinity bin that wasn't generated by this repository? The bins generated by this repository fit the box generated by this repository, but they don't match the gridfinity spec - they are narrower at the base; such that:

Here's a comparison of the imported STEP from gridfinitybox 1 1 6 (pink, the profile at the bottom) and a standard gridfinity box: image

Clearly - the wider yellow box won't descend past the matching upper slope of your boxes.

Again - the gridfinity spec is this (gridfinity.xyz, also replicated here): image (Edit: To point out that as this was copied from earlier these are the baseplate specs; the bin base specs are very slightly different for tolerances) 2.15mm height at 45°, 1.8mm vertical, then another 0.7mm at 45°. You can see the proportions don't match this on the cross-section you just posted.

I took a look at this after seeing someone complaining that they had printed a box from this repository without double checking and it wasn't at all compatible, e.g. wasted filament.

ndevenish commented 8 months ago

The good news is that if the ruggedbox baseplate is fixed, then it will continue accepting all of the boxes generated before the fix.

But, if you fix the bins then any bins generated after the fix will no longer fix the ruggedbox printed before the fix.

So you might have to keep the bins as they are, just slightly out-of-spec, and just fix the bases. Or hope that not many people printed the box (which would be a pity, they look nice).

michaelgale commented 8 months ago

Thanks for the additional clarifications. In order to see what is going on, let's look at each issue individually.

  1. The cq-gridfinity bin:

As far as I can tell, the bins/boxes generated by cq-gridfinity (GridfinityBox) do conform to the specification:

binspec

Unless I am misunderstanding the specification? (always a possibility!)

  1. The cq-gridfinity baseplate profile:

Again, I could be misunderstanding the specification, but when comparing the spec with the generated baseplate profile in the rugged box I see that it more or less conforms:

basespec

Obviously, any deviations from the accepted specification should be changed in this package--its just not clear to me where the deviation resides? Am I using an outdated specification?

michaelgale commented 8 months ago

And just for completeness, here is a dimensioned view from inside the ruggedbox:

ruggeddim
ndevenish commented 8 months ago

This is what I get measuring a similar corner image

ndevenish commented 8 months ago

The spec images you linked to are correct, the generated geometry isn't.

Hmm, this is cadquery 2.4.0 off of conda-forge. I'll try working out how to get cadquery working inside a docker environment.

michaelgale commented 8 months ago

Woah! That is way off! This deviation smells a lot like a sqrt(2) scaling issue...the profile for the boxes and baseplates is specified in terms of vertical offsets and angles. CadQuery performs extrusions in terms of vertical distance or vertical distance + taper angle. Therefore, if you have a taper angle (e.g. 45º), then you have to scale your offset accordingly. Thus, in cq-gridfinity, the profiles defined in constants.py show these SQRT2 corrections. I wonder if CadQuery has changed the way the extrude method works since 2.4.0???

ndevenish commented 8 months ago

I'm also unsure exactly which portion of the baseplate your view is of. None of the joints look like that on mine, they all look like my image above

ndevenish commented 8 months ago

I'm trying downgrading CadQuery.

ndevenish commented 8 months ago

FWIW this might explain why the label was also wrong; we had assumed the model was just incomplete when looking at it image

FWIW this is one of the things I hated about OpenSCAD. Good for basic shapes, but anything trying to approach filleting/chamfer any actual polish always felt like a massive fudge, and something I wasn't supposed to be doing.

michaelgale commented 8 months ago

I think I might be finding some more clues. It might be a my fault introducing a regression error by changing a function used by cq-gridfinity contained in the helper package cq-kit. cq-kit has a helper function to help with multi-level extrusions which has a automatic compensation for vertical projection based on taper angle. This compensation is new and therefore, it has likely broken cq-gridfinity. Stay tuned as I confirm the root cause.

ndevenish commented 8 months ago

Confirmed that downgrading to cadquery 2.3.1 fixes the issue (and the label)

ndevenish commented 8 months ago

I’m glad that it was neither of us going crazy, which I was starting to doubt for a moment there.

michaelgale commented 8 months ago

@ndevenish Thanks for the catch on this. The error was indeed due to different versions of CadQuery/cq-kit/cq-gridfinity. A new version of cq-gridfinity v.0.4.3 is available on pypi. Can you please install v.0.4.3 and see if that works with CQ 2.4.0 (and other versions if possible)?

michaelgale commented 8 months ago

FYI, this bug also explains the weird appearance of the label window too. Any feature which depended on multilevel extruded geometry would have been affected.

ndevenish commented 8 months ago

I've tested repo HEAD on CQ 2.3.1 and 2.4.0. 2.3.1 works but it looks like I still get the same behaviour (for both) in CQ 2.4.0.

I didn't test pypi directly as I had a struggle getting that to work initially (lack of arm wheels for... something in the dependency chain including cadquery - I initially tried to pipx install and got the same missing module error others have seen)

I haven't spent the time to work out exactly what this is doing, and have no idea if this aids debugging, but amending the change in that commit with:

--- a/cqgridfinity/gf_obj.py
+++ b/cqgridfinity/gf_obj.py
@@ -313,9 +313,12 @@ class GridfinityObject:
         p0 = profile[0][0] if isinstance(profile[0], (list, tuple)) else profile[0]
         r = cq.Workplane(workplane).placeSketch(sketch).extrude(p0, taper=taper)
         for level in profile[1:]:
+            print(f"Path taken on level {level}:")
             if isinstance(level, (tuple, list)):
+                print("  Is tuple, list")
                 r = r.faces(">Z").wires().toPending().extrude(level[0], taper=level[1])
             else:
+                print("  The Other Path")
                 r = r.faces(">Z").wires().toPending().extrude(level)
         return r

I get:

% ruggedbox 4 5 6

 ____                             _ ____
|  _ \ _   _  __ _  __ _  ___  __| | __ )  _____  __
| |_) | | | |/ _` |/ _` |/ _ \/ _` |  _ \ / _ \ \/ /
|  _ <| |_| | (_| | (_| |  __/ (_| | |_) | (_) >  <
|_| \_\\__,_|\__, |\__, |\___|\__,_|____/ \___/_/\_\
             |___/ |___/

Version: 0.4.3
Gridfinity rugged box: 4U x 5U x 6U (168.0 mm x 210.0 mm x 45.8 mm)
  Wall Vgrooves      : Y
  Front Handle       : Y
  Stackable          : Y
  Side Clasps        : Y
  Lid Baseplate      : Y
  Inside Baseplate   : Y
  Side Handles       : Y
  Front Label        : Y
  Back Feet          : Y
Rendering full assembly...
Path taken on level (1.4142135623730951, 45):
  Is tuple, list
Path taken on level (1.4142135623730951, -45):
  Is tuple, list
Path taken on level 23:
  The Other Path
Path taken on level (1.4142135623730951, 45):
  Is tuple, list
Path taken on level (1.4142135623730951, -45):
  Is tuple, list
Path taken on level 9:
  The Other Path
 Path taken on level 1.8:
  The Other Path
Path taken on level (0.9849999999999999, 45):
  Is tuple, list
Path taken on level 1.6:
  The Other Path
Path taken on level (1.4142135623730951, 45):
  Is tuple, list
Path taken on level (1.4142135623730951, -45):
  Is tuple, list
Path taken on level 23:
  The Other Path
Path taken on level (1.4142135623730951, 45):
  Is tuple, list
Path taken on level (1.4142135623730951, -45):
  Is tuple, list
Path taken on level 9:
  The Other Path
Path taken on level (1.0, -45):
  Is tuple, list
Path taken on level 2.4965001794687494:
  The Other Path
Path taken on level 0.4:
  The Other Path
Path taken on level (5, -45):
  Is tuple, list
%
michaelgale commented 8 months ago

I would try the above test with generating simple 1x1 gridfinity bin. You should see the above trace with the expected gridfinity intervals for describing the bottom of a bin as well as describing the top lip.

ndevenish commented 8 months ago
% gridfinitybox 1 1 6

  _____      _     _  __ _       _ _           ____
 / ____|    (_)   | |/ _(_)     (_) |         |  _ \
| |  __ _ __ _  __| | |_ _ _ __  _| |_ _   _  | |_) | _____  __
| | |_ | '__| |/ _` |  _| | '_ \| | __| | | | |  _ < / _ \ \/ /
| |__| | |  | | (_| | | | | | | | | |_| |_| | | |_) | (_) >  <
 \_____|_|  |_|\__,_|_| |_|_| |_|_|\__|\__, | |____/ \___/_/\_\
                                        __/ |
                                       |___/

Version: 0.4.3
Gridfinity box: 1U x 1U x 6U (42.0 mm x 42.0 mm x 45.8 mm), 1.00 mm walls
Path taken on level 1.8:
  The Other Path
Path taken on level (1.13, 45):
  Is tuple, list
Path taken on level (2.2627416997969525, 45):
  Is tuple, list
Path taken on level 1.2:
  The Other Path
Path taken on level (0.9899494936611666, -45):
  Is tuple, list
Path taken on level 1.8:
  The Other Path
Path taken on level (1.8384776310850237, -45):
  Is tuple, list
Path taken on level 1.8:
  The Other Path
Path taken on level (1.13, 45):
  Is tuple, list
Path taken on level (2.2627416997969525, 45):
  Is tuple, list
Path taken on level 1.2:
  The Other Path
Path taken on level (0.9899494936611666, -45):
  Is tuple, list
Path taken on level 1.8:
  The Other Path
Path taken on level (1.8384776310850237, -45):
  Is tuple, list

Box generated and saved as gf_box_1x1x6.step in STEP format

Geometry is wrong (and also has a weird dogleg at the top, next to the 2): image

ndevenish commented 8 months ago

I even renamed before importing into fusion, in case it was doing any weird cacheing.

happy to run a heavily annotated branch, if it would help

michaelgale commented 8 months ago

Interesting. I run the exact same code with debug reporting as yours and it reports the same (correct) extrusion intervals. However, the generated STEP file I get is also correct; whereas yours is clearly not. Therefore, it must be something in CadQuery. FYI, I am runnning CQ 2.2.0.

michaelgale commented 8 months ago

Found it! Looks like a change was made to CadQuery to compensate for extrusion height: https://github.com/CadQuery/cadquery/issues/1383. This completely explains it. Looks like I will have to add some code to version check the CQ API and then determine if correction to vertical extrusion height is required or not. Stay tuned.

michaelgale commented 8 months ago

@ndevenish I've committed cq-gridfinity v.0.4.4 with changes which should hopefully detect which version of CadQuery's extrusion method is active and therefore decide whether or not to apply compensation to the extruded profile. Can you please test with this update with CQ 2.4.0?

michaelgale commented 8 months ago

I've updated a new version v.0.4.5 which (hopefully) finally fixes the extrusion angle errors independent of CadQuery version.

ndevenish commented 8 months ago

Partial success, with a couple of roadbumps. Firstly:

  File "/Users/nickd/3d/cadquery/cq-gridfinity/cqgridfinity/gf_obj.py", line 34, in <module>
    from cqkit import export_step_file, size_3d
ImportError: cannot import name 'size_3d' from 'cqkit' (/Users/nickd/3d/cadquery/ENV/lib/python3.12/site-packages/cqkit/__init__.py)

size_3d was added in cqkit 0.5.3 (2f80bc), but was only exported to the root init.py afterwards, which didn't make it into a release yet. So it probably needs to be from cqkit.cq_helpers import size_3d (I don't know why this would have worked?).

Installing from the main branch of the cqkit repository gets past this. Then, the 1x1 bin generates successfully! It's probably close enough - certainly it will fit - but the geometry is still a bit strange; this is an orthographic axis-aligned projection: image

vs what I would expect: image

However, I don't know if these are "Working as intended" features and thus unrelated to this version-shear issue.

Anyhow, with the latest unreleased cqkit the RuggedBox still fails to generate:

Traceback (most recent call last):
  File "/Users/nickd/3d/cadquery/ENV/bin/ruggedbox", line 33, in <module>
    sys.exit(load_entry_point('cqgridfinity', 'console_scripts', 'ruggedbox')())
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/nickd/3d/cadquery/cq-gridfinity/cqgridfinity/scripts/ruggedbox.py", line 363, in main
    a = box.render_assembly()
        ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/nickd/3d/cadquery/cq-gridfinity/cqgridfinity/gf_ruggedbox.py", line 967, in render_assembly
    r = self.render()
        ^^^^^^^^^^^^^
  File "/Users/nickd/3d/cadquery/cq-gridfinity/cqgridfinity/gf_ruggedbox.py", line 860, in render
    r = r.edges(vs).fillet(2.5)
        ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/nickd/3d/cadquery/ENV/lib/python3.12/site-packages/cadquery/cq.py", line 1302, in fillet
    raise ValueError("Fillets requires that edges be selected")
ValueError: Fillets requires that edges be selected

Apologies, but I unfortunately don't have any more time to spend debugging this tonight, so am going to have to step away for a bit.

michaelgale commented 8 months ago

@ndevenish Thanks so much for your help and testing--much appreciated. Looks like there are a couple more items to clean up (e.g. inconsistent imports from cq-kit). The marginally close geometry is likely due to round off residue in the SQRT2 scaling and is likely tolerable for almost all applications. The ruggedbox fillet issue is not one that I have seen, but I'll have a look--I suspect its dependency issue with CadQuery or cq-kit and might also have a platform dependency.

michaelgale commented 8 months ago

A new version v.0.5.0 has been updated with various improvements to the rugged box. I am not sure if this will fix the "fillet" issue above (although that section of code has been changed to make it more robust). The biggest improvements are checks and automatic re-dimensioning of features such as the label, handles, etc. for boxes smaller than the original intended box size of 4U x 4U x 6U. cq-gridfinity can now make viable rugged boxes down to a minimum of 3U x 3U x 4U. The length x width minimum is bounded by the corner reinforcements and hinges and the height minimum is bounded by the function of the latch.

michaelgale commented 8 months ago

v.0.5.1 now includes increased resolution for the vertical profiles of baseplates and bins. You should see better agreement of dimensions with the gridfinity specification.

ndevenish commented 8 months ago

Yes! On main the geometry appears much cleaner now, and all of the joints just appear to be a single vertex after importing. thanks!

tehfishmann commented 8 months ago

I, however, appear to be hilariously cursed. This is running on the latest python:3.11 docker image. I get the same results running outside of a container, but I tried the container approach to guarantee a clean environment.

root@22227b4462cf:/# ruggedbox 5 4 6

 ____                             _ ____
|  _ \ _   _  __ _  __ _  ___  __| | __ )  _____  __
| |_) | | | |/ _` |/ _` |/ _ \/ _` |  _ \ / _ \ \/ /
|  _ <| |_| | (_| | (_| |  __/ (_| | |_) | (_) >  <
|_| \_\\__,_|\__, |\__, |\___|\__,_|____/ \___/_/\_\
             |___/ |___/

Version: 0.5.1
Gridfinity rugged box: 5U x 4U x 6U (210.0 mm x 168.0 mm x 45.8 mm)
  Wall Vgrooves      : Y
  Front Handle       : Y
  Stackable          : Y
  Side Clasps        : Y
  Lid Baseplate      : Y
  Inside Baseplate   : Y
  Side Handles       : Y
  Front Label        : Y
  Back Feet          : Y
Rendering full assembly...
Traceback (most recent call last):
  File "/usr/local/bin/ruggedbox", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/usr/local/lib/python3.11/site-packages/cqgridfinity/scripts/ruggedbox.py", line 364, in main
    a = box.render_assembly()
        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/cqgridfinity/gf_ruggedbox.py", line 992, in render_assembly
    r = self.render()
        ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/cqgridfinity/gf_ruggedbox.py", line 884, in render
    r = r.edges("|Z").edges(vs).fillet(2.5)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/cadquery/cq.py", line 1304, in fillet
    s = solid.fillet(radius, edgeList)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/cadquery/occ_impl/shapes.py", line 2780, in fillet
    return self.__class__(fillet_builder.Shape())
                          ^^^^^^^^^^^^^^^^^^^^^^
OCP.StdFail.StdFail_NotDone: BRep_API: command not done
root@22227b4462cf:/# python --version
Python 3.11.8
root@22227b4462cf:/# pip freeze | grep -E "(cq|gridfinity|cadquery)"
cadquery==2.4.0
cadquery-ocp==7.7.2
cqgridfinity==0.5.1
cqkit==0.5.3

Commands I used to set up the environment:

# req for cadquery
apt update; apt install libgl1-mesa-glx -y
pip install cqgridfinity
michaelgale commented 8 months ago

@ndevenish Excellent--glad to hear all is ok! Thanks again for your help.

@tehfishmann Since your issue seems to be confined to rendering the side handles of the rugged box, I would try to render a nearly featureless box first. This would at least sanity check that it is building something viable. Then, I would add features to see if and when it breaks. For example, to build the same 5x4x6 box with no features:

ruggedbox 5 4 6 -e -v -s -c -a -p -l

then add side clasps and stackability:

ruggedbox 5 4 6 -e -v +s +c -a -p -l

then add a handle and front label:

ruggedbox 5 4 6 -e -v +s +c +a -p +l

finally add the side handles:

ruggedbox 5 4 6 +e -v +s +c +a -p +l

Of course, you can change up the combo of features to experiment, but the idea is to see if it is some combo of features that results in a broken model which makes the addition of the side handles break.

tehfishmann commented 8 months ago

Appears to just be the side handles - generates just fine with -e. As far as viability goes, I did notice that the locating features on the fully rendered box aren't actually attached to the box, so it wouldn't print successfully. It's almost like the top surface got pushed down by 2 mm or so, since the front handle features are also poking up over the edge, and in the fully rendered view the lid is floating over the box. I think this is related to the failing side handles given their location on the object. Everything else looked about right though; grid dimensions now measure correctly and should work just fine.

Ortho view from the front: image

michaelgale commented 8 months ago

@ndevenish The geometry has been optimized further (mainly on the inside) such that floor and lip intervals coincide with exact 7.00mm intervals. Furthermore, the lower bin draft terminates at 4.75 mm instead of 5.00 mm

michaelgale commented 8 months ago

@tehfishmann Thanks for the tests. One thing that sticks out to me is that the V-grooves on the side walls are not correct. Can you please try to render version(s) of the box without V-grooves, i.e. using -v?

michaelgale commented 8 months ago

@tehfishmann For reference, this is the expected front view:

ruggedfront
michaelgale commented 8 months ago

@tehfishmann I've pushed a new release v.0.5.3 which removed a potential namespace collision when computing the height of boxes/bins. This might explain the unusual vertical placement of objects on the model; however, it is not definitive since theorectically the collision should not occur. In any case, worth a try if you have a moment.

tehfishmann commented 8 months ago

The behavior appears to be the same in 0.5.4; crash when using all features, no crash when removing sidehandles but then the vertical alignment is off.

I did try disabling the vgroove and that fixes the height of the top surface, and doing so also allows the generation of the sidehandles. It would seem as though they are mutually exclusive at the moment.

michaelgale commented 8 months ago

@tehfishmann Thanks for the update. I have just pushed a new release v.0.5.5 which might offer a fix for the ruggedbox--although I suspect it will remain the same.

tehfishmann commented 8 months ago

That actually seems to have fixed it! I examined 4 test cases and they all looked correct; all features, no side handles, no v-groove, and one with no handles and no v-groove all generated as expected. Thanks for all the work you put in on this, the models look really great

michaelgale commented 8 months ago

@tehfishmann Excellent! Glad to hear it! Thanks for running the test cases to find clues to eventually make it work.

@ndevenish If you folks are ok with the latest release in terms of addressing both the dimensional issues and the broken rugged box--feel free to close out the issue. Coincidentally, the root cause for both issues was the erroneous vertical extrusion scaling as a result of changes in CadQuery. Thankfully, this bug lead to optimizing the geometry so that it is completely compliant with the latest Gridfinity spec.

michaelgale commented 8 months ago

Closing out this issue as resolved as of v.0.5.5.

@ndevenish @tehfishmann Thanks again for your assistance.