diff options
Diffstat (limited to 'pizerow.scad')
| -rw-r--r-- | pizerow.scad | 464 |
1 files changed, 464 insertions, 0 deletions
diff --git a/pizerow.scad b/pizerow.scad new file mode 100644 index 0000000..47c90dd --- /dev/null +++ b/pizerow.scad @@ -0,0 +1,464 @@ +/* + A box for the pizero(/w). + Designed to allow the pizero to be completely in the box, resiliant to + dust and pokey fingers. + + * Configurable connector holes + * Either holes, for screws/bolts, or mounting pins for the pizero + * Engineering model of a pizero, so you can check if it looks right + - remember to turn this off before generating an STL + + TODO: + * Calculate everything, remove magic numbers + * Cut outs the gland on the lid to allow connectors right into the pizero +*/ + +// THINGIVERSE customizer does not understand true/flase, so use 1/0 instead + +/* [parts] */ +make_bottom=1; // [0:No,1:Yes] +make_top=0; // [0:No,1:Yes] + +/* [connectors] */ +sdcard_hole = 1; // [0:No,1:Yes] +power_hole = 1; // [0:No,1:Yes] +hdmi_hole = 1; // [0:No,1:Yes] +usb_hole = 1; // [0:No,1:Yes] +camera_hole = 0; // [0:No,1:Yes] +gpio_hole = 1; // [0:No,1:Yes] +pins = 1; // [0:No,1:Yes] + +/* [box] */ +// gap around pizero inside the box +gap = 1.0; +// wall thickness of box +shell_thickness = 1.2; +// standoffs pizero sits on in the box +standoffs = 1.5; + +/* [Text on lid] */ +// Add an engraved text on the top, 'help->font list' for available +add_text = 1; // [0:No,1:Yes] +lid_text = "pizerow"; +text_font="Comic Sans MS"; + +/* [pizero options] */ +// show an engineering model +dummy_pizero = 0; // [0:No,1:Yes] +// do we need height for a header +//pz_header = 0; // not tested, problems with heights +// allow for solder on bottom, standoffs take care of this +//pz_solder = 0; // don't need to allow for this as we have standoffs + +// the pizero engineering model with the measurements we use, includes don't work in thingiverse customizer +//include <pizerow.scad>; + +////////////////////////////// +// +// Start of included pizero engineering model +// +//////////////////// +/* [pizero dimensions DO NOT ALTER] */ +pz_length = 65; // not including sd card protrusion +pz_width = 30; // not including any connector protrusions +pz_pcb_thickness = 1.45; // including solder mask +pz_component_max_height = (3.1 - pz_pcb_thickness); // hdmi is max +pz_rounded_edge_offset = 3.0; +pz_botton_pin_height = 1.0; // solder pins for gpio connector + +pz_mount_hole_dia = 2.75; +pz_mount_hole_offset = 3.5; // from edge +pz_mount_hole_dia_clearance = 6; + +pz_gpio_length = 50.8; // total +pz_gpio_width = 5; // total +pz_gpio_x_offset = 32.5; // from left hand edge to centre of connector +pz_gpio_y_offset = 3.5; // long edge centre form pcb edge +pz_gpio_height = (9.8 - pz_pcb_thickness); // wihtout pcb thickness + +pz_sdcard_y_offset = 16.9; +pz_sdcard_length = 15.4; // sdcard present +pz_sdcard_width = 12; +pz_sdcard_protrusion = 2.3; // sdcard present +pz_sdcard_height = (2.8 - pz_pcb_thickness); + +pz_camera_y_offset = 15; +pz_camera_length = 4.43; +pz_camera_width = 17; +pz_camera_protrusion = 1.1; // no cable present +pz_camera_height = (2.65 - pz_pcb_thickness); + +pz_hdmi_x_offset = 12.4; +pz_hdmi_length = 11.2; +pz_hdmi_width = 7.6; +pz_hdmi_protrusion = 0.5; // no cable present +pz_hdmi_height = (4.7 - pz_pcb_thickness); + +pz_usb_power_x_offset = 54; +pz_usb_x_offset = 41.4; +pz_usb_length = 8; +pz_usb_width = 5.6; +pz_usb_protrusion = 1; // no cable present +pz_usb_height = (3.96 - pz_pcb_thickness); + +pz_max_length = pz_length + pz_sdcard_protrusion + pz_camera_protrusion; +pz_max_width = pz_width + pz_usb_protrusion; +/////////////////////////////////// +// +// End of pizero definitions +// +//////////////////// + +////////////////////////////////// +// +// Start of pizero functions/modules +// +//////////////////////// +function pz_get_max_height(gpio_header, gpio_solder) = + pz_pcb_thickness + + (pz_botton_pin_height * (gpio_solder?1:0)) + + (pz_gpio_height * (gpio_header?1:0)) + + (pz_component_max_height * (gpio_header?0:1)); + + +module pzw(gpio_header = true, gpio_solder = true) { + + pz_max_height = pz_get_max_height(gpio_header, gpio_solder); + + echo("pi max length ", pz_max_length); + echo("pi max width ", pz_max_width); + echo("pi max height ", pz_max_height); + + module pzw_solid() { + // rounded edges on pcb + x_round = [pz_rounded_edge_offset, (pz_length - pz_rounded_edge_offset)]; + y_round= [pz_rounded_edge_offset, (pz_width - pz_rounded_edge_offset)]; + for (x = x_round, y = y_round) + translate([x, y, 0]) + { + $fn = 40; + cylinder(d=(2*pz_rounded_edge_offset), h=pz_pcb_thickness); + } + + // pcb split into bits to conform with rounded edges + translate([pz_rounded_edge_offset, 0, 0]) + cube([pz_length - (2 * pz_rounded_edge_offset), pz_width, pz_pcb_thickness]); + translate([0, pz_rounded_edge_offset, 0]) + cube([pz_length, pz_width - (2 * pz_rounded_edge_offset), pz_pcb_thickness]); + + // gpio + if (gpio_header) + translate([pz_gpio_x_offset-(pz_gpio_length/2), + (pz_width-pz_gpio_y_offset-(pz_gpio_width/2)), + pz_pcb_thickness]) + cube([pz_gpio_length, pz_gpio_width, pz_gpio_height]); + + // gpio underside solder + if (gpio_solder) + translate([pz_gpio_x_offset-(pz_gpio_length/2), + (pz_width-pz_gpio_y_offset-(pz_gpio_width/2)), + -pz_botton_pin_height]) + cube([pz_gpio_length, pz_gpio_width, pz_botton_pin_height]); + + // sdcard + translate([-pz_sdcard_protrusion, + (pz_sdcard_y_offset-(pz_sdcard_width/2)), + pz_pcb_thickness]) + cube([pz_sdcard_length, pz_sdcard_width, pz_sdcard_height]); + + // camera + translate([(pz_length - pz_camera_length + pz_camera_protrusion), + (pz_camera_y_offset-(pz_camera_width/2)), + pz_pcb_thickness]) + cube([pz_camera_length, pz_camera_width, pz_camera_height]); + + // hdmi + translate([(pz_hdmi_x_offset - (pz_hdmi_length/2)), + -pz_hdmi_protrusion, + pz_pcb_thickness]) + cube([pz_hdmi_length, pz_hdmi_width, pz_hdmi_height]); + + // usb power + translate([(pz_usb_power_x_offset - (pz_usb_length/2)), + -pz_usb_protrusion, + pz_pcb_thickness]) + cube([pz_usb_length, pz_usb_width, pz_usb_height]); + + // usb + translate([(pz_usb_x_offset - (pz_usb_length/2)), + -pz_usb_protrusion, + pz_pcb_thickness]) + cube([pz_usb_length, pz_usb_width, pz_usb_height]); + } + + // make 0,0,0 centre + translate([pz_camera_protrusion+pz_camera_protrusion-pz_max_length/2, + pz_usb_protrusion-pz_max_width/2, + 0]) + difference () { + pzw_solid(); + + // mounting holes + x_holes = [pz_mount_hole_offset, (pz_length - pz_mount_hole_offset)]; + y_holes = [pz_mount_hole_offset, (pz_width - pz_mount_hole_offset)]; + for (x = x_holes, y = y_holes) + translate([x, y, -pz_pcb_thickness]) + { + $fn = 40; + cylinder(d=pz_mount_hole_dia, h=10); + } + } +} +//////////////////////////////////////// +// +// End of pizero functions/modules +// +//////////////////////////// + +case_inside_length = pz_max_length + 2*gap; +case_inside_width = pz_max_width + 2*gap; +case_inside_height = pz_get_max_height(true, true) + standoffs; + +case_outside_length = case_inside_length + (2*shell_thickness); +case_outside_width = case_inside_width + (2*shell_thickness); +case_outside_height = case_inside_height; //+ (2*shell_thickness); + +module rounded_box(length, + width, + height, + rounded_edge_radius) +{ + + // rounded edges + x_round = [rounded_edge_radius, (length - rounded_edge_radius)]; + y_round= [rounded_edge_radius, (width - rounded_edge_radius)]; + for (x = x_round, y = y_round) + translate([x, y, 0]) + { + $fn = 40; + cylinder(d=(2*rounded_edge_radius), h=height); + } + + // pcb split into bits to conform with rounded edges + translate([rounded_edge_radius, 0, 0]) + cube([length - (2 * rounded_edge_radius), + width, + height]); + translate([0, rounded_edge_radius, 0]) + cube([length, + width - (2 * rounded_edge_radius), + height]); +} + +module shell(inside_length, + inside_width, + inside_height, + thickness, + rounded_edge_radius) +{ + difference () + { + // outside + translate([-thickness, -thickness, -thickness]) + rounded_box(case_outside_length, + case_outside_width, + case_outside_height, + rounded_edge_radius); + + // inside, remove top by extending it through the outside + rounded_box(inside_length, inside_width, case_outside_height+1, rounded_edge_radius); + + if (sdcard_hole) { + offset = 10.4 + gap; // magic number for centre line + translate([-case_outside_length/8, offset, standoffs+pz_pcb_thickness/2]) + #cube([case_outside_length/4, pz_sdcard_width+3, 4]); + } + + if (usb_hole) { + offset = 37.9 + gap; + translate([offset, -case_outside_width/4, standoffs-0.6]) + #cube([pz_usb_length+3.5, case_outside_length/4, 7]); + } + + if (power_hole) { + offset = 50.5 + gap; + translate([offset, -case_outside_width/4, standoffs-0.6]) + #cube([pz_usb_length+3.5, case_outside_length/4, 7]); + } + + // hole for camera + if (camera_hole) { + offset = 8.5 + gap; + translate([case_outside_length/1.25, offset, (standoffs+pz_pcb_thickness)]) + #cube([case_outside_length/4, pz_camera_width-2, 1.2]); + } + if (hdmi_hole) { + offset = 7.3 + gap; + translate([offset, -case_outside_width/4, standoffs+pz_pcb_thickness/2]) + #cube([pz_hdmi_length+3.5, case_outside_length/4, 5]); + } + } +} + +module bottom_shell() { + translate([-case_inside_length/2, -case_inside_width/2, 0]) + shell(case_inside_length, + case_inside_width, + case_inside_height, + shell_thickness, + pz_rounded_edge_offset); + + // mounting standoffs and pins for pizero + translate([pz_camera_protrusion+pz_camera_protrusion-pz_max_length/2, + pz_usb_protrusion-pz_max_width/2, 0]) + { + x_pins = [pz_mount_hole_offset, (pz_length - pz_mount_hole_offset)]; + y_pins = [pz_mount_hole_offset, (pz_width - pz_mount_hole_offset)]; + for (x = x_pins, y = y_pins) + translate([x, y, 0]) + { + $fn = 40; + cylinder(d=pz_mount_hole_dia_clearance, h=standoffs); + translate([0, 0, standoffs]) + if (pins) + { + // allow for some slack in the hole diameter, 0.9 + // pins longer then pcb is thick so pcb can't slip out + cylinder(d=(pz_mount_hole_dia*0.9), h=3*pz_pcb_thickness); + } + } + } + + // for reference we can add a dummy pizero + if (dummy_pizero) { + color("yellow") + translate([0, 0, standoffs]) // add 20 for outside box + pzw(true, true); + } +} + + +module bottom() { + difference() + { + bottom_shell(); + // holes right through instead of pins + if (!pins) + { + translate([pz_camera_protrusion+pz_camera_protrusion-pz_max_length/2, + pz_usb_protrusion-pz_max_width/2, 0]) + { + x_pins = [pz_mount_hole_offset, (pz_length - pz_mount_hole_offset)]; + y_pins = [pz_mount_hole_offset, (pz_width - pz_mount_hole_offset)]; + for (x = x_pins, y = y_pins) + translate([x, y, 0]) + { + $fn = 40; + translate([0, 0, -2*shell_thickness]) + #cylinder(d=(pz_mount_hole_dia*1.1), h=2*case_inside_height); + } + } + } + } +} + +module top_with_rim() { + // add an extra layer on top to cover the gpio hole + lid_thickness = (gpio_hole)?(shell_thickness):(shell_thickness+1); + rounded_box(case_outside_length, case_outside_width, lid_thickness, pz_rounded_edge_offset); + + // need to make a rim/gland + translate([shell_thickness, shell_thickness, -2*shell_thickness]) + { + // translate to make sure that rim is part of the top + translate([0,0,0.5]) + difference() + { + rounded_box(case_outside_length - 2*shell_thickness, + case_outside_width - 2*shell_thickness, + 2*shell_thickness, + pz_rounded_edge_offset); + + // make a gland type rim by extending through the inside box + translate([shell_thickness, shell_thickness, -shell_thickness]) + rounded_box(case_inside_length - 2*shell_thickness, + case_inside_width - 2*shell_thickness, + 3*shell_thickness, + pz_rounded_edge_offset); + } + } +} + +module top () { + color("orange") + + translate([-case_inside_length/2-shell_thickness, + -case_inside_width/2-shell_thickness, + case_outside_height+shell_thickness]) + difference () + { + top_with_rim(); + + // always cut out for gpio pins + offset_x = 9.9 + gap; // magic numbers + offset_y = 25.4 + gap; + translate([offset_x, offset_y, -3*shell_thickness]) + #cube([pz_gpio_length+2, + pz_gpio_width+2, + 4*shell_thickness+0.3]); + + // a notch to make taking top of easier + translate([0, 10+gap, -0.1]) + cube([shell_thickness, + 15, + shell_thickness*0.6]); + + // text, really deep text if we have no gpio cutout + if(add_text) + { + translate([case_outside_length/2,case_outside_width*0.5,shell_thickness*0.5]) + linear_extrude(5, convexity=4) + text(lid_text, font=text_font, valign="center", halign="center"); + } + } + + if (pins) + { + // add locking pins to lid + // values iteratively found + translate([pz_camera_protrusion+pz_camera_protrusion-pz_max_length/2, + pz_usb_protrusion-pz_max_width/2, + case_outside_height - 2.9*shell_thickness]) + { + x_pins = [pz_mount_hole_offset, (pz_length - pz_mount_hole_offset)]; + y_pins = [pz_mount_hole_offset, (pz_width - pz_mount_hole_offset)]; + for (x = x_pins, y = y_pins) + translate([x, y, 0]) + { + //translate([0, 0, -2*shell_thickness]) + difference () + { + $fn = 40; + length = 6.6; //magic + #cylinder(d=pz_mount_hole_dia_clearance*0.9, h=length); + #cylinder(d=pz_mount_hole_dia*1.1, h=length); + } + } + } + + } +} + +/* +// something doesn't add up, measured prints do not equate +echo("inside length ", case_inside_length); +echo("inside width ", case_inside_width); +echo("inside height ", case_inside_height); + +echo("outside length ", case_outside_length); +echo("outside width ", case_outside_width); +echo("outside height ", case_outside_height); +*/ + +if (make_bottom) bottom(); +if (make_top) top(); |
