3d-printing/raskog-separator/separator.scad
Felipe M. 676ffe37c5 Add RASKOG magnetic Skadis separator and skadis-board library
New lib/skadis-board generator produces a parametric IKEA Skadis-compatible
pegboard panel (40mm grid + 20mm offset grid), with standard and dense
density modes that both stay accessory-compatible.

New raskog-separator project: a customizable RASKOG cart divider whose
vertical wall is a Skadis panel, standing on an inverted-T magnetic foot.
Magnets glue into pockets that open at the bottom of the flange wings so
they sit flush against the basket's steel mesh; size/count/rows configurable.
2026-06-03 22:38:24 +02:00

219 lines
9.9 KiB
OpenSCAD

// ============================================
// RASKOG Magnetic Skadis Separator
// ============================================
// A customizable divider for the IKEA RASKOG cart. The vertical wall is
// itself an IKEA Skadis pegboard panel, so real Skadis accessories hang on
// the divider. It stands on a wide magnetic foot whose magnets grab the
// steel wire-mesh floor of the RASKOG basket to hold the divider in place.
//
// The Skadis hole pattern comes from the shared lib/skadis-board generator
// (40mm grid + 20mm offset grid), with selectable standard/dense density —
// both stay compatible with off-the-shelf Skadis accessories.
//
// Magnets are glued into pockets that open at the BOTTOM of the foot's two
// flange wings, so each magnet sits flush against the steel mesh for the
// strongest hold. Pick bigger/more magnets for an even stronger grip.
//
// Print standing exactly as modeled (foot flat on the bed, wall up) — it is
// support-free apart from the few-mm ceiling each magnet pocket bridges over.
// Use a brim for the tall thin wall if your printer needs one.
//
// RASKOG basket interior (measured at the floor; walls taper inward):
// bottom 288 x 405, middle 284 x 397, top 278 x 389 mm.
// The default wall_width spans the short axis with clearance for the taper.
//
// Coordinate system:
// Origin (0, 0, 0) = center of the foot footprint, on the basket floor.
// X = wall length (along the basket axis being divided)
// Y = thin direction (foot width + wall thickness)
// Z = up
use <../lib/skadis-board/skadis-board.scad>;
// ============================================
// CUSTOMIZABLE PARAMETERS
// ============================================
/* [Separator Wall] */
// Wall length (X, mm). Default spans the RASKOG short axis with clearance.
wall_width = 270; // [40:1:400]
// Skadis board height above the foot (Z, mm)
wall_height = 80; // [40:1:200]
// Board thickness (mm). Keep ~5 for Skadis accessory compatibility.
wall_thickness = 5.0; // [4:0.1:6]
// Hole pattern: standard Skadis checkerboard, or denser full 20mm grid
wall_density = "dense"; // [standard, dense]
// Slot short axis (Skadis nominal 5mm)
wall_slot_width = 5.0; // [4:0.1:8]
// Slot long axis (Skadis nominal 15mm)
wall_slot_height = 15.0; // [10:0.1:25]
// Countersink at each slot mouth (mm); 0 = sharp slot
wall_edge_chamfer = 1.0; // [0:0.1:3]
// Outer board corner radius (mm)
wall_corner_r = 4; // [0:0.5:15]
/* [Magnetic Foot] */
// Foot flange total width (Y, mm) — the wide base that resists tipping
foot_flange_w = 34; // [12:1:80]
// Foot flange height (Z, mm) — must contain the magnet pocket + floor
foot_flange_h = 6; // [3:0.5:20]
// Central neck width (Y, mm) — must be >= wall_thickness
neck_w = 6; // [3:0.5:20]
// Top of the neck where the wall begins (Z, mm)
foot_height = 12; // [6:1:40]
// Chamfer on the foot's bottom edges to avoid an elephant-foot lip (mm)
foot_edge_chamfer = 1.0; // [0:0.1:4]
// Concave fillet where the neck meets the flange top (mm) — strength
join_fillet_r = 2.0; // [0:0.5:8]
// How far the wall base sinks into the neck for a solid union (mm)
merge_overlap = 3; // [1:0.1:8]
/* [Magnets] */
// Magnet disc diameter (mm)
magnet_diameter = 6; // [3:0.5:20]
// Magnet disc height/thickness (mm)
magnet_height = 3; // [1:0.5:6]
// Magnet rows: 2 = one per wing (default, anti-tip), 1 = single offset row
magnet_rows = 2; // [1, 2]
// Magnets along the foot in each row
magnet_per_row = 6; // [1:1:30]
// Radial clearance around each magnet (glue gap, mm)
magnet_fit_clear = 0.2; // [0:0.05:0.6]
// How far the magnet sits above the bottom face (mm) — 0 = flush with the
// foot bottom for the strongest grip; raise to recess/protect the magnet
magnet_recess = 0.0; // [0:0.1:3]
// Distance from the foot ends to the first/last magnet (mm)
magnet_inset = 18; // [5:1:80]
/* [Resolution] */
$fn = 64;
// ============================================
// DERIVED DIMENSIONS
// ============================================
foot_length = wall_width; // foot runs the full length of the wall
hf = foot_flange_w / 2; // flange half-width (Y)
nf = neck_w / 2; // neck half-width (Y)
pocket_r = magnet_diameter / 2 + magnet_fit_clear;
// Y of each magnet row: centered in the wing region that is clear of the
// neck-to-flange fillet, so the magnet never collides with the fillet.
wing_center_y = (nf + join_fillet_r + hf) / 2;
wall_z = foot_height - merge_overlap; // board base Z (sunk into the neck)
total_height = wall_z + wall_height; // overall part height (info)
// ============================================
// PARAMETER VALIDATION
// ============================================
assert(wall_width > 0 && wall_height > 0, "wall_width and wall_height must be positive");
assert(wall_thickness >= 4 && wall_thickness <= 6,
"wall_thickness should be ~5mm for Skadis accessory compatibility");
assert(foot_flange_w > neck_w, "foot_flange_w must be greater than neck_w");
assert(neck_w >= wall_thickness, "neck_w must be >= wall_thickness so the wall seats on the foot");
assert(foot_height > foot_flange_h, "foot_height must be greater than foot_flange_h (the neck rises above the flange)");
assert(magnet_recess >= 0, "magnet_recess must be non-negative");
assert(foot_flange_h >= magnet_recess + magnet_height + 0.8,
"foot_flange_h too small: needs magnet_recess + magnet_height + >=0.8mm cap above the magnet");
assert(magnet_diameter > 0 && magnet_height > 0, "magnet dimensions must be positive");
assert(magnet_rows == 1 || magnet_rows == 2, "magnet_rows must be 1 or 2");
assert(magnet_per_row >= 1, "magnet_per_row must be >= 1");
assert(magnet_fit_clear >= 0, "magnet_fit_clear must be non-negative");
assert(wing_center_y - pocket_r >= nf + join_fillet_r,
"magnet pocket overlaps the neck/fillet — widen the flange or shrink the magnet");
assert(wing_center_y + pocket_r <= hf - foot_edge_chamfer - 0.5,
"magnet pocket too close to the flange edge — widen the flange or shrink the magnet");
assert(2 * magnet_inset < foot_length, "magnet_inset too large for the foot length");
assert(magnet_per_row == 1
|| (foot_length - 2 * magnet_inset) >= (magnet_per_row - 1) * (magnet_diameter + 2 * magnet_fit_clear + 2),
"not enough foot length to fit magnet_per_row pockets without overlap");
assert(merge_overlap > 0 && merge_overlap < foot_height && merge_overlap < wall_height,
"merge_overlap must fit within both the neck and the wall");
assert(foot_edge_chamfer >= 0 && 2 * foot_edge_chamfer < foot_flange_w
&& foot_edge_chamfer < foot_flange_h,
"foot_edge_chamfer must fit within the flange");
assert(join_fillet_r >= 0 && join_fillet_r <= (foot_flange_w - neck_w) / 2
&& join_fillet_r <= (foot_height - foot_flange_h),
"join_fillet_r must fit within the flange-to-neck step");
// ============================================
// MAIN ASSEMBLY
// ============================================
separator();
module separator() {
union() {
magnetic_foot();
translate([-wall_width / 2, -wall_thickness / 2, wall_z])
skadis_board(
width = wall_width,
height = wall_height,
thickness = wall_thickness,
density = wall_density,
slot_w = wall_slot_width,
slot_h = wall_slot_height,
edge_chamfer = wall_edge_chamfer,
corner_r = wall_corner_r);
}
}
// ============================================
// COMPONENT MODULES
// ============================================
// Inverted-T foot: a wide flat flange (the basket-floor footprint) with a
// narrow central neck the wall seats on. Magnet pockets are subtracted from
// the flange wings. Built by extruding the Y-Z cross-section along X.
module magnetic_foot() {
difference() {
rotate([90, 0, 90]) // map 2D (u,v) -> (Y, Z); extrude along X
linear_extrude(height = foot_length, center = true)
polygon(_foot_profile(
hf = hf, nf = nf, ch = foot_edge_chamfer,
fh = foot_flange_h, th = foot_height, jf = join_fillet_r));
magnet_pockets();
}
}
// 2D cross-section of the foot in the Y-Z plane (first coord = Y, second = Z).
// Symmetric inverted-T: chamfered bottom flange + concave fillets where the
// vertical neck meets the flange top.
function _foot_profile(hf, nf, ch, fh, th, jf, n_arc = 12) =
let (
// Left inside fillet: flange top (z=fh) up to neck wall (Y=-nf).
left_fillet = [
for (i = [0 : n_arc])
let (a = -90 + 90 * i / n_arc)
[(-nf - jf) + jf * cos(a), (fh + jf) + jf * sin(a)]
],
// Right inside fillet: neck wall (Y=nf) down to flange top (z=fh).
right_fillet = [
for (i = [0 : n_arc])
let (a = 180 + 90 * i / n_arc)
[(nf + jf) + jf * cos(a), (fh + jf) + jf * sin(a)]
]
)
concat(
[[-(hf - ch), 0], [-hf, ch], [-hf, fh]],
left_fillet,
[[-nf, th], [nf, th]],
right_fillet,
[[hf, fh], [hf, ch], [hf - ch, 0]]
);
// Glue-in magnet pockets: vertical bores opening at the BOTTOM of the flange
// wings. The magnet is glued in from below, seating against the pocket
// ceiling magnet_recess above the bottom face; the solid cap above it is
// what the print bridges over.
module magnet_pockets() {
rows_y = (magnet_rows == 2) ? [-wing_center_y, wing_center_y] : [wing_center_y];
for (y = rows_y)
for (x = _magnet_x_positions())
translate([x, y, -1])
cylinder(h = magnet_recess + magnet_height + 1, r = pocket_r);
}
// Evenly spaced magnet X positions within the inset span (centered if one).
function _magnet_x_positions() =
let (span = foot_length / 2 - magnet_inset)
(magnet_per_row == 1)
? [0]
: [ for (i = [0 : magnet_per_row - 1]) -span + 2 * span * i / (magnet_per_row - 1) ];