Skip to main content
F3D
Kệ Gridfinity OpenGrid hỗ trợ Multiconnect gắn nam châm 1

2 images

DIY

Kệ Gridfinity OpenGrid hỗ trợ Multiconnect gắn nam châm

Remix of Kệ treo tường đa năng tích hợp Gridfinity cho hệ thống openGrid By DavidD

By Ai Power Power

Likes
1
Views
32

Files 2 9.1 MB

  • opengrid_multiconnect_gridfinity_shelf_magnets_1x2_1783592282.stlSTL · 1.7 MB
  • opengrid_multiconnect_gridfinity_shelf_magnets_2x4_1783592283.stlSTL · 7.4 MB

Make a variant with AI

Build another version of this model.

Open Studio

Description

using the openscad designs from https://github.com/AndyLevesque/QuackWorks and https://github.com/kennetek/gridfinity-rebuilt-openscad I added the magnets to this. 

LLM was used to add in the new code for the magnet holes and magnet removal methods. It also re-wrote the crush ribs for the magnets

/*Created by BlackjackDuck (Andy)
Credit to
@David D on Printables for Multiboard
Jonathan at Keep Making for Multiconnect
Zach at gridfinity.xyz for the Gridfinity standard
Katie (and her community) at Hands on Katie on Youtube for advice
@Dontic on GitHub for Multiconnect v2 code
Additional credit:
@kennetek on GitHub for the ribbed/crush-fit magnet hole concept, adapted
from the ribbed_cylinder technique in gridfinity-rebuilt-openscad
(https://github.com/kennetek/gridfinity-rebuilt-openscad), used under the
MIT License. Reimplemented here as ribbed_press_circle/ribbed_press_cylinder
rather than copied directly.

Licensed Creative Commons 4.0 Attribution Non-Commercial Share-alike with Attribution

TODO:
- Add ability to tweak rim height
- Ability to trim grid height (some versions lop off a tiny bit off the top)

Change Log:
- 2024-09-01
- Initial release
- 2025-04-08
- New backs (Multipoint, openGrid, GOEWS)
-2025-07-15
- New Multiconnect v2 option added with improved holding (thanks @dontic on GitHub!)

Local modifications:
- Added corner magnet holes, press-fit from the top surface, cut into the
shelf floor slab (see the Magnets section below).
- Optional ribbed (wavy crush-fit) hole style, inspired by the ribbed_cylinder
technique in kennetek/gridfinity-rebuilt-openscad (MIT licensed).
- Optional slot/hole magnet removal assist, slots cut diagonally toward the
nearest open cell corner.
*/
include <BOSL2/std.scad>

/[Slot Types]/
//How do you intend to mount to a surface and which surface?
Connection_Type = "Multiconnect - openGrid"; // [Multipoint, Multiconnect - Multiboard, Multiconnect - openGrid, Multiconnect - Custom Size, GOEWS]

/[Parameters]/
unitsWide = 4;
unitsDeep = 2;
rimThickness = 1.5;
additionalRimHeight = 2;
baseThickness = 4;
overrideBackHeight = false;
customBackHeight = 60;
backHeight = overrideBackHeight ? customBackHeight : 15+15*unitsDeep;
removeBase = false;
bracketDepthPercentage = 50; //[0:1:100]

/[Magnets]/
// Enable magnets in each gridfinity cell corner
Enable_Magnets = true;
//size of magnet, diameter and height. Zack's original used 6.5 and 2.4
Magnet_Size = [6.5, 2.4]; // .1
//solid material left below the magnet so it can't push through the floor
Magnet_Floor_Below = 1.0; // .1
//Press-fit style: "smooth" (plain reduced-diameter hole) or "ribbed" (wavy crush-fit, more tolerant of printer variance)
Magnet_Fit_Style = "ribbed"; // [smooth, ribbed]
//shrinks the hole radius below magnet radius. For "ribbed" this can be small/zero since the ribs do the gripping; for "smooth" this is the entire fit.
Magnet_Press_Fit_Reduction = 0.05; // .05
//Number of crush ribs around the hole (ribbed style only)
Magnet_Rib_Count = 12;
//How far the ribs bulge in/out from the nominal radius (ribbed style only)
Magnet_Rib_Depth = 0.15; // .05
//lead-in chamfer at the top opening so the magnet is easy to start pressing in
Magnet_Chamfer = 0.4; // .1
//Distance magnet hole center sits from each cell edge (gridfinity standard is 8mm)
Magnet_Inset = 8;
//Method to help remove magnets: "none", "slot" (screwdriver pry notch, cut diagonally toward the nearest open corner), "hole" (poke-out hole from underneath), "both"
Magnet_Release_Method = "hole"; //[none, slot, hole, both]
//Width of the pry notch, for a small flathead screwdriver tip
Release_Slot_Width = 3.5; // .1
//How far the pry notch cuts down from the top surface
Release_Slot_Depth = 1.5; // .1
//Diameter of the poke-out hole through the floor
Release_Hole_Diameter = 3; // .1

/[Slot Customization]/
// Version of multiconnect (dimple or snap)
multiConnectVersion = "v2"; // [v1, v2]
onRampHalfOffset = true;
//Distance between Multiconnect slots on the back (25mm is standard for MultiBoard)
customDistanceBetweenSlots = 25;
//Reduce the number of slots
subtractedSlots = 0;
//QuickRelease removes the small indent in the top of the slots that lock the part into place
slotQuickRelease = false;
//Dimple scale tweaks the size of the dimple in the slot for printers that need a larger dimple to print correctly
dimpleScale = 1; //[0.5:.05:1.5]
//Scale the size of slots in the back (1.015 scale is default for a tight fit. Increase if your finding poor fit. )
slotTolerance = 1.00; //[0.925:0.005:1.075]
//Move the slot in (positive) or out (negative)
slotDepthMicroadjustment = 0; //[-.5:0.05:.5]
//enable a slot on-ramp for easy mounting of tall items
onRampEnabled = true;
//frequency of slots for on-ramp. 1 = every slot; 2 = every 2 slots; etc.
On_Ramp_Every_X_Slots = 1;
//Distance from the back of the item holder to where the multiconnect stops (i.e., where the dimple is) (by mm)
Multiconnect_Stop_Distance_From_Back = 13;

onRampEveryXSlots = On_Ramp_Every_X_Slots;

/[GOEWS Customization]/
GOEWS_Cleat_position = "normal"; // [normal, top, bottom, custom]
GOEWS_Cleat_custom_height_from_top_of_back = 11.24;

/[Hidden]/
magnets_active = Enable_Magnets && !removeBase;
magnetStackHeight = Magnet_Size[1] + Magnet_Floor_Below;
effectiveBaseThickness = magnets_active ? max(baseThickness, magnetStackHeight) : baseThickness;
adjustedBaseThickness = removeBase ? 0 : effectiveBaseThickness;
totalWidth = unitsWide42+rimThickness2;
totalDepth = unitsDeep42+rimThickness;
bracketDepth = totalDepth
bracketDepthPercentage/100;
totalHeight = backHeight;

distanceBetweenSlots =
Connection_Type == "Multiconnect - openGrid" ? 28 :
Connection_Type == "Multiconnect - Custom Size" ? customDistanceBetweenSlots :
25; //default for multipoint

Connection_Standard =
Connection_Type == "Multipoint" ? "Multipoint" :
Connection_Type == "Multiconnect - Multiboard" ? "Multiconnect" :
Connection_Type == "Multiconnect - openGrid" ? "Multiconnect" :
Connection_Type == "Multiconnect - Custom Size" ? "Multiconnect" :
Connection_Type == "GOEWS" ? "GOEWS" :
"Unknown";

//begin build
translate(v = [-totalWidth/2,-totalDepth/2])
union(){
translate(v = [rimThickness,0,0])
gridfinity_grid(xCount = unitsWide, yCount = unitsDeep);
//BEGIN BACKERS
if(Connection_Standard == "Multipoint"){
translate(v = [0,0,-adjustedBaseThickness])
makebackPlate(
backWidth = totalWidth,
backHeight = totalHeight,
distanceBetweenSlots = distanceBetweenSlots,
backThickness=4.8);
}
if(Connection_Standard == "Multiconnect"){
translate(v = [0,0,-adjustedBaseThickness])
makebackPlate(
backWidth = totalWidth,
backHeight = totalHeight,
distanceBetweenSlots = distanceBetweenSlots,
backThickness=6.5);
}
if(Connection_Standard == "GOEWS"){
translate(v = [0,0,-adjustedBaseThickness])
makebackPlate(
backWidth = totalWidth,
backHeight = totalHeight,
distanceBetweenSlots = 42,
backThickness=7
);
}
//END BACKERS

//shelf
difference(){
translate(v = [0,0,-adjustedBaseThickness+0.01])
cube([totalWidth,totalDepth,4.65+adjustedBaseThickness+additionalRimHeight]);
translate(v = [rimThickness,0,0])
cube([totalWidth-rimThickness2-0.02,totalDepth-rimThickness-0.02,6+additionalRimHeight]);
//magnet press-fit pockets, opening on the top surface of the floor
if (magnets_active)
translate(v = [rimThickness,0,0])
for (cellY = [0:1:unitsDeep-1])
for (cellX = [0:1:unitsWide-1])
translate([cellX
42, cellY*42, 0])
gridfinity_magnet_press_pockets(
inset = Magnet_Inset,
magnetSize = Magnet_Size,
floorThickness = adjustedBaseThickness,
pressFitReduction = Magnet_Press_Fit_Reduction,
chamfer = Magnet_Chamfer,
fitStyle = Magnet_Fit_Style,
ribCount = Magnet_Rib_Count,
ribDepth = Magnet_Rib_Depth,
releaseMethod = Magnet_Release_Method,
slotWidth = Release_Slot_Width,
slotDepth = Release_Slot_Depth,
releaseHoleDiameter = Release_Hole_Diameter
);
}
//bracket
exposedBackHeight = backHeight-adjustedBaseThickness-4.65;
translate(v = [rimThickness,0,backHeight-adjustedBaseThickness])
shelfBracket(bracketHeight = exposedBackHeight, bracketDepth = bracketDepth,rimThickness = rimThickness);
translate(v = [totalWidth,0,backHeight-adjustedBaseThickness])
shelfBracket(bracketHeight = exposedBackHeight, bracketDepth = bracketDepth,rimThickness = rimThickness);
}

module gridfinity_grid(xCount, yCount) {
//Gridfinity Grid
for (columnY = [0:1:yCount-1]){
for (rowX = [0:1:xCount-1]) {
translate(v = [rowX42,columnY42,0]) gridfinity_base();
}
}
}

module gridfinity_base() {
difference() {
cube(size = [42,42,4.65]);
/*
baseplate delete tool
This is a delete tool which is the inverse profile of the baseplate intended for Difference.
Using polygon, I sketched the profile of the base edge per gridfinity specs.
I then realized I need rounded corners with 8mm outer diameter, so I increased the x axis enough to have a 4mm total outer length (radius).
I rotate extrude to created the rounded corner
Finally, I used minkowski (thank you Katie from "Hands on Katie") using a cube that is 42mm minus the 8mm of the edges (equalling 34mm)
I also added separate minkowski tools to extend the top and the bottom for proper deleting
*/
union() {
//primary profile
translate(v = [4,38,5.65])
rotate(a = [180,0,0])
minkowski() {
rotate_extrude($fn=50)
polygon(points = [[0,0],[4,0],[3.3,0.7],[3.3,2.5],[1.15,4.65],[0,4.65]]);
cube(size = [34,34,1]);
}
//bottom extension bottom tool
translate(v = [4,4,-2])
minkowski() {
linear_extrude(height = 1) circle(r = 4-2.85, $fn=50);
cube(size = [34,34,6]);
}
//top extension
translate(v = [4,4,5])
minkowski() {
linear_extrude(height = 1) circle(r = 4, $fn=50);
cube(size = [34,34,2]);
}
}
}
}

//BEGIN MODULES

// Wavy crush-fit circle: wraps a sine wave around the nominal radius so the
// hole flexes slightly on insertion instead of relying purely on a fixed
// diameter tolerance. Same underlying idea as gridfinity-rebuilt-openscad's
// ribbed_cylinder (MIT licensed), reimplemented to match this file's style.
module ribbed_press_circle(radius, ribDepth, ribs) {
points = [
for (a = [0 : 360/max($fn, 60) : 360])
[sin(a), cos(a)] * (radius + sin(a * ribs) * ribDepth)
];
polygon(points);
}

module ribbed_press_cylinder(radius, ribDepth, ribs, height) {
linear_extrude(height)
ribbed_press_circle(radius, ribDepth, ribs);
}

// Press-fit magnet pockets, opening on the TOP surface of the floor (z=0, the
// surface bins sit on). Magnet is pushed in by hand after printing.
// fitStyle "smooth": plain reduced-radius hole, friction from pressFitReduction alone.
// fitStyle "ribbed": wavy crush-fit hole, ribs do most of the gripping.
// Solid material below (floorThickness - magnetSize[1]) stops the magnet from
// pushing through to the underside.
// Optional removal assist: a side pry notch ("slot", cut diagonally toward the
// nearest open cell corner), a poke-out hole from underneath ("hole"), or both.
module gridfinity_magnet_press_pockets(inset = 8, magnetSize = [6.5, 2.4], floorThickness = 3.4, pressFitReduction = 0.15, chamfer = 0.4, fitStyle = "smooth", ribCount = 12, ribDepth = 0.15, releaseMethod = "none", slotWidth = 3.5, slotDepth = 1.5, releaseHoleDiameter = 3) {
r = (magnetSize[0] - pressFitReduction) / 2;
h = magnetSize[1];

for (xi = [0, 1]) {
for (yi = [0, 1]) {
x = (xi == 0) ? inset : 42 - inset;
y = (yi == 0) ? inset : 42 - inset;
// direction toward the nearest open corner of the cell, for the pry notch
xSign = (xi == 0) ? -1 : 1;
ySign = (yi == 0) ? -1 : 1;
diagonalAngle = atan2(-ySign, -xSign);

translate([x, y, 0]) {
union() {
// press-fit hole: smooth (plain cylinder) or ribbed (crush-fit)
translate([0, 0, -h])
if (fitStyle == "ribbed")
ribbed_press_cylinder(radius = r, ribDepth = ribDepth, ribs = ribCount, height = h + 0.01);
else
cylinder(h = h + 0.01, r = r, $fn = 48);

// lead-in chamfer right at the opening
if (chamfer > 0)
translate([0, 0, -chamfer])
cylinder(h = chamfer + 0.01, r1 = r, r2 = r + chamfer, $fn = 48);

// pry notch: cut diagonally outward toward the nearest open cell
// corner (not straight along X), so the notch lands where there's
// actually open space to slide a screwdriver in, rather than
// potentially running into a neighboring cell or the tray wall.
if (releaseMethod == "slot" || releaseMethod == "both")
rotate([0, 0, diagonalAngle])
translate([r - 0.5, -slotWidth/2, -slotDepth])
cube([r + 1.5, slotWidth, slotDepth + 0.01]);

// poke-out hole: straight through from the TRUE underside of the
// floor up to the bottom of the magnet pocket.
if ((releaseMethod == "hole" || releaseMethod == "both") && floorThickness > h)
translate([0, 0, -floorThickness - 0.5])
cylinder(h = (floorThickness - h) + 0.5, r = releaseHoleDiameter/2, $fn = 30);
}
}
}
}
}

module shelfBracket(bracketHeight, bracketDepth, rimThickness){
rotate(a = [-90,0,90])
linear_extrude(height = rimThickness)
polygon([[0,0],[0,bracketHeight],[bracketDepth,bracketHeight]]);
}

//Slotted back Module
module makebackPlate(backWidth, backHeight, distanceBetweenSlots, backThickness, slotStopFromBack = 13, edgeRounding = 1)
{
//slot count calculates how many slots can fit on the back. Based on internal width for buffer.
//slot width needs to be at least the distance between slot for at least 1 slot to generate
let (backWidth = max(backWidth,distanceBetweenSlots), backHeight = max(backHeight, 25),slotCount = floor(backWidth/distanceBetweenSlots)- subtractedSlots){
if(Connection_Standard != "GOEWS"){
difference() {
translate(v = [0,-backThickness,0])
cuboid(size = [backWidth,backThickness,backHeight], rounding=edgeRounding, edges=FRONT, except_edges=BOT, anchor=FRONT+LEFT+BOT, $fn = 25);
//Loop through slots and center on the item
//Note: I kept doing math until it looked right. It's possible this can be simplified.
for (slotNum = [0:1:slotCount-1]) {
translate(v = [distanceBetweenSlots/2+(backWidth/distanceBetweenSlots-slotCount)distanceBetweenSlots/2+slotNumdistanceBetweenSlots,-2.35+slotDepthMicroadjustment,backHeight-Multiconnect_Stop_Distance_From_Back]) {
if(Connection_Standard == "Multipoint"){
multiPointSlotTool(totalHeight);
}
if(Connection_Standard == "Multiconnect"){
multiConnectSlotTool(totalHeight);
}
}
}
}
} else {
// GOEWS
GOEWS_Cleat_custom_height_from_top_of_back = (GOEWS_Cleat_position == "normal") ? 11.24 : (GOEWS_Cleat_position == "top") ? 0 : (GOEWS_Cleat_position == "bottom") ? backHeight - 13.15 : GOEWS_Cleat_custom_height_from_top_of_back;

difference() {
union() {
// Back plate
translate(v = [0,-backThickness,0])
cuboid(size = [backWidth,backThickness,backHeight], rounding=edgeRounding, except_edges=BACK, anchor=FRONT+LEFT+BOT);
//Loop through slots and center on the item
//Note: I kept doing math until it looked right. It's possible this can be simplified.
// Add cleats
for (slotNum = [0:1:slotCount-1]) {
translate(v = [distanceBetweenSlots/2+(backWidth/distanceBetweenSlots-slotCount)distanceBetweenSlots/2+slotNumdistanceBetweenSlots,-1 * backThickness,backHeight-GOEWS_Cleat_custom_height_from_top_of_back]) {
GOEWSCleatTool(totalHeight);
}
}
};
// Remove back plate cut outs for screw threads
for (slotNum = [0:1:slotCount-1]) {
translate(v = [distanceBetweenSlots/2+(backWidth/distanceBetweenSlots-slotCount)distanceBetweenSlots/2+slotNumdistanceBetweenSlots, 0, backHeight + 0.46 - GOEWS_Cleat_custom_height_from_top_of_back + 11.24]) {

Read more Show less

Read the whole body (10,077 characters left)

Print spec

Formats
stl
Model files
2
Total size
9.1 MB
Largest file
7.4 MB

0 comments

See all