455 lines
15 KiB
Plaintext
455 lines
15 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "71c5d64a",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from solid import *\n",
|
|
"import viewscad\n",
|
|
"import numpy as np\n",
|
|
"\n",
|
|
"\n",
|
|
"def yp(y:float) -> OpenSCADObject:\n",
|
|
" return translate((0, y, 0))\n",
|
|
"\n",
|
|
"def ym(y: float) -> OpenSCADObject:\n",
|
|
" return translate((0, -y, 0))\n",
|
|
"\n",
|
|
"def xp(x: float) -> OpenSCADObject:\n",
|
|
" return translate((x, 0, 0))\n",
|
|
"\n",
|
|
"def xm(x: float) -> OpenSCADObject:\n",
|
|
" return translate((-x, 0, 0))\n",
|
|
"\n",
|
|
"def zp(z: float) -> OpenSCADObject:\n",
|
|
" return translate((0, 0, z))\n",
|
|
"\n",
|
|
"def zm(z: float) -> OpenSCADObject:\n",
|
|
" return translate((0, 0, -z))\n",
|
|
"\n",
|
|
"def wedge(height_dir : int, width_dir: int, start_point, width, height, extent, straight_section=0):\n",
|
|
" dtype = type(start_point[0])\n",
|
|
" e_width = np.array([0, 0, 0], dtype=dtype)\n",
|
|
" e_width[width_dir] = width\n",
|
|
" e_height = np.array([0, 0, 0], dtype=dtype)\n",
|
|
" e_height[height_dir] = height\n",
|
|
" e_height_s = np.array([0, 0, 0], dtype=dtype)\n",
|
|
" e_height_s[height_dir] = straight_section\n",
|
|
" outward_dir = ({0, 1, 2} - {height_dir, width_dir}).pop()\n",
|
|
" e_outward = np.array([0, 0, 0], dtype=dtype)\n",
|
|
" e_outward[outward_dir] = extent\n",
|
|
"\n",
|
|
" start_point = np.array(start_point, dtype=dtype)\n",
|
|
" start_point += e_height_s\n",
|
|
" \n",
|
|
" p0 = start_point \n",
|
|
" p1 = start_point + e_height\n",
|
|
" p2 = p1 + e_width\n",
|
|
" p3 = p2 - e_height\n",
|
|
" p4 = p3 + e_outward\n",
|
|
" p5 = p0 + e_outward\n",
|
|
" \n",
|
|
" faces = [\n",
|
|
" (0, 3, 4, 5), # top\n",
|
|
" (3, 0, 1, 2),\n",
|
|
" (4, 2, 1, 5), # \n",
|
|
" (0, 5, 1), # front\n",
|
|
" (4, 3, 2), # back\n",
|
|
" ]\n",
|
|
" result = polyhedron(points = [p0, p1, p2, p3, p4, p5], faces=faces)\n",
|
|
" if straight_section > 0:\n",
|
|
" cube_origin = start_point - e_height_s\n",
|
|
" result += translate(cube_origin)(cube(e_outward + e_height_s + e_width))\n",
|
|
" return result\n",
|
|
"\n",
|
|
"def wedge_by_angle(height_dir : int, width_dir: int, start_point, width, degrees, extent, straight_section=0):\n",
|
|
" height = abs(int(extent / np.tan(np.deg2rad(degrees))))\n",
|
|
" \n",
|
|
" return wedge(height_dir, width_dir, start_point, width, height, extent, straight_section)\n",
|
|
"\n",
|
|
"\n",
|
|
"r = viewscad.Renderer()\n",
|
|
"\n",
|
|
"#r.render(wedge_by_angle(1, 2, (0, 0, 0), 40, degrees=20, extent=20, straight_section=15))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "0612a43c",
|
|
"metadata": {},
|
|
"source": [
|
|
"# SwimTracker Case\n",
|
|
"\n",
|
|
"all units in tenth of mm\n",
|
|
"\n",
|
|
"## A) Dimensions of contained parts"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "69f72329",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Load Cell\n",
|
|
"\n",
|
|
"load cell is aligned such that cable outlet is at top right, \n",
|
|
"\n",
|
|
"$z$ axis is parallel to screws, $y$ is the larger size, $x$ the smaller size"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "b979fa4a",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_load_cell_dims():\n",
|
|
" size = (400, 1300, 220)\n",
|
|
" d = 125 # distance between screw and next side\n",
|
|
" screw_midpoints = [\n",
|
|
" (d, d), (size[0] - d, d), # bottom two screws\n",
|
|
" (d, size[1] - d), (size[0] -d, size[1] - d), # top two screws,\n",
|
|
" (size[0] / 2, 2 * d), # bottom middle screw\n",
|
|
" (size[0] / 2, size[1] - 2 * d), # top middle screw\n",
|
|
" ]\n",
|
|
" return {'size': size, \n",
|
|
" 'screw_midpoints': screw_midpoints}\n",
|
|
"\n",
|
|
"load_cell_dims = make_load_cell_dims()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "198286e2",
|
|
"metadata": {},
|
|
"source": [
|
|
"### PCB"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"id": "4b17b3f1",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_pcb_dims():\n",
|
|
" pcb_thickness = 16\n",
|
|
" pin_space_below = 25\n",
|
|
" component_max_height = 100\n",
|
|
" total_height = pcb_thickness + pin_space_below + component_max_height\n",
|
|
" \n",
|
|
" return {\n",
|
|
" 'size': (400, 800, total_height),\n",
|
|
" 'pin_space_below': pin_space_below,\n",
|
|
" 'pcb_thickness': pcb_thickness,\n",
|
|
" }\n",
|
|
"pcb_dims = make_pcb_dims()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "f36ade54",
|
|
"metadata": {},
|
|
"source": [
|
|
"## B) Parameters"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"id": "6ac51708",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"wall_thickness = 30\n",
|
|
"wedge_angle = 20 # in degrees\n",
|
|
"\n",
|
|
"# Tolerances\n",
|
|
"tol_around_lcell = 20\n",
|
|
"tol_pcb_slide = 5\n",
|
|
"\n",
|
|
"bottom_lip = 100 # how much longer the case is in y direction below the size of the load cell\n",
|
|
"cable_space = 60 # how much space left/right to put the cable in\n",
|
|
"separator_size = (wall_thickness, 190, 70) # 4 walls that fix load cell at the top and separate load cell & cable\n",
|
|
"#pcb_rails_size = (50, pcb_dims['size'][1], wall_thickness) # 4 rails that hold pcb in place\n",
|
|
"#pcb_rail_stopper_height = 0 # straight part after PCB rails (if 0 wedge starts right away)\n",
|
|
"\n",
|
|
"\n",
|
|
"interior_size = (load_cell_dims['size'][0] + 2 * tol_around_lcell + 2 * cable_space + 2 * separator_size[0],\n",
|
|
" load_cell_dims['size'][1] + bottom_lip,\n",
|
|
" load_cell_dims['size'][2] + 2 * tol_around_lcell + pcb_dims['size'][2] + wall_thickness)\n",
|
|
"size = tuple(s + 2 * wall_thickness for s in interior_size)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"id": "c22da25a",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"580"
|
|
]
|
|
},
|
|
"execution_count": 5,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"load_cell_dims['size'][0] + 2 * cable_space + 2 * separator_size[0]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "9778b756",
|
|
"metadata": {},
|
|
"source": [
|
|
"## C) Upper Part"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"id": "98eeee57",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"(620, 1400, 431)\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"def make_upper_part(with_screw_holes):\n",
|
|
" # shortcuts\n",
|
|
" lcell_size = load_cell_dims['size']\n",
|
|
" wt = wall_thickness\n",
|
|
" \n",
|
|
" # dims\n",
|
|
" bottom_lip = 100 # how much longer the case is in y direction below the size of the load cell\n",
|
|
" cable_space = 60 # how much space left/right to put the cable in\n",
|
|
" separator_size = (wall_thickness, 190, 70) # 4 walls that fix load cell at the top and separate load cell & cable\n",
|
|
" pcb_rails_size = (70, pcb_dims['size'][1], wt) # 4 rails that hold pcb in place\n",
|
|
" pcb_rail_stopper_height = 0\n",
|
|
" \n",
|
|
" interior_size = (lcell_size[0] + 2 * tol_around_lcell + 2 * cable_space + 2 * separator_size[0],\n",
|
|
" lcell_size[1] + bottom_lip,\n",
|
|
" lcell_size[2] + 2 * tol_around_lcell + pcb_dims['size'][2] + wt)\n",
|
|
" print(interior_size)\n",
|
|
" size = tuple(s + 2 * wall_thickness for s in interior_size)\n",
|
|
" \n",
|
|
" # outer wall\n",
|
|
" def interior_coords(e):\n",
|
|
" return translate([wt, bottom_lip + wt, wt])(e)\n",
|
|
" outer_wall = cube(size) - translate([wt, 0, wt])(cube([interior_size[0], interior_size[1] + wt, interior_size[2]]))\n",
|
|
" \n",
|
|
" # pcb rails\n",
|
|
" rail_space_to_wall = min(pcb_rails_size[2], pcb_dims['pin_space_below'] - pcb_rails_size[2])\n",
|
|
" rail_z_extent = 2 * pcb_rails_size[2] + pcb_dims['pcb_thickness'] + tol_pcb_slide + rail_space_to_wall\n",
|
|
" \n",
|
|
" rail_wedge_height = pcb_rails_size[1] + pcb_rail_stopper_height\n",
|
|
" rail_wedge_left = wedge_by_angle(1, 2, (0, rail_wedge_height, interior_size[2] - rail_z_extent), rail_z_extent, wedge_angle, pcb_rails_size[0])\n",
|
|
" rail_wedge_right = wedge_by_angle(1, 2, (interior_size[0], rail_wedge_height, interior_size[2] - rail_z_extent), rail_z_extent, wedge_angle, -pcb_rails_size[0])\n",
|
|
"\n",
|
|
" stopper = yp(pcb_rails_size[1])(cube([pcb_rails_size[0], pcb_rail_stopper_height, rail_z_extent]))\n",
|
|
" pcb_rails_left = zp(interior_size[2] - rail_space_to_wall - wt)(cube([pcb_rails_size[0], pcb_rails_size[1], rail_space_to_wall + pcb_rails_size[2]]) + zm(pcb_dims['pcb_thickness'] + tol_pcb_slide + pcb_rails_size[2])(stopper + cube(pcb_rails_size)))\n",
|
|
" pcb_rails_right = xp(interior_size[0] - pcb_rails_size[0])(pcb_rails_left)\n",
|
|
" \n",
|
|
" pcb_rails = interior_coords(pcb_rails_left + pcb_rails_right + rail_wedge_left + rail_wedge_right)\n",
|
|
" \n",
|
|
" # load cell cap\n",
|
|
" y_off = lcell_size[1] - separator_size[1]\n",
|
|
" x_off_right = interior_size[0] - cable_space - separator_size[0]\n",
|
|
" \n",
|
|
" load_cell_cap_gen = yp(y_off)(cube([separator_size[0], separator_size[1], interior_size[2]]))\n",
|
|
" load_cell_cap_left = xp(cable_space)(load_cell_cap_gen)\n",
|
|
" load_cell_cap_right = xp(x_off_right)(load_cell_cap_gen)\n",
|
|
" cable_cutout = xp(x_off_right)(yp(y_off)(zp(separator_size[2])(cube([separator_size[0], separator_size[1], lcell_size[2] + 2 * tol_around_lcell - 2 * separator_size[2]])))) \n",
|
|
" load_cell_cap_cross = translate([0, y_off, lcell_size[2] + 2 * tol_around_lcell])((cube([interior_size[0], separator_size[1], separator_size[0]])))\n",
|
|
" load_cell_cap = interior_coords(load_cell_cap_left + (load_cell_cap_right - cable_cutout) + load_cell_cap_cross)\n",
|
|
" \n",
|
|
" \n",
|
|
" # wedges for cap\n",
|
|
" cap_wedge_y = 0\n",
|
|
" cap_wedge_width = load_cell_dims['size'][2] + 2 * tol_around_lcell\n",
|
|
" cap_wedge_straight_thickness = 50\n",
|
|
" cap_wedge_x = cable_space + wt\n",
|
|
" cap_wedge_left = wedge_by_angle(1, 2, (0, 0, cap_wedge_y), cap_wedge_width, wedge_angle, cap_wedge_x, cap_wedge_straight_thickness)\n",
|
|
" cap_wedge_right = wedge_by_angle(1, 2, (interior_size[0], 0, cap_wedge_y), cap_wedge_width, wedge_angle, -cap_wedge_x, cap_wedge_straight_thickness)\n",
|
|
" cap_wedges = interior_coords(cap_wedge_left + cap_wedge_right)\n",
|
|
"\n",
|
|
" # screw holes\n",
|
|
" lower_screw = load_cell_dims['screw_midpoints'][-2]\n",
|
|
" upper_screw = load_cell_dims['screw_midpoints'][-1]\n",
|
|
" screw_x_offset = cable_space + wt + tol_around_lcell\n",
|
|
" hole_eps = 2\n",
|
|
" screw_diameter = 75\n",
|
|
" screw_hole_upper = translate([screw_x_offset + upper_screw[0], upper_screw[1], -hole_eps / 2 + interior_size[2]])(cylinder(d=screw_diameter, center=False, h= wt + 2* hole_eps))\n",
|
|
" screw_hole_lower = translate([screw_x_offset + lower_screw[0], lower_screw[1], -hole_eps / 2 - wt])(cylinder(d=screw_diameter, center=False, h= wt + 2* hole_eps))\n",
|
|
" screw_holes = interior_coords(screw_hole_upper + screw_hole_lower)\n",
|
|
" \n",
|
|
" if with_screw_holes:\n",
|
|
" return (outer_wall + hole()(screw_holes)) + pcb_rails + load_cell_cap + cap_wedges\n",
|
|
" else:\n",
|
|
" return outer_wall + pcb_rails + load_cell_cap + cap_wedges\n",
|
|
"\n",
|
|
"upper_part = make_upper_part(True)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cec5b185",
|
|
"metadata": {},
|
|
"source": [
|
|
"## D) Lower Part (Cap)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"id": "a377d2ff",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_lower_part():\n",
|
|
" return cube([interior_size[0], wall_thickness, interior_size[2]])\n",
|
|
"\n",
|
|
"lower_part = make_lower_part()\n",
|
|
"#done directly in blender"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "e57a5d44",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Renders"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"id": "19c5c826",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"display_scale = 0.001 # just for display in notebook\n",
|
|
"output_scale = 0.1 # in mm"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"id": "caafb3cd",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#scad_render_to_file(scale(output_scale)(lower_part), \"lower_part.scad\")\n",
|
|
"#r.render(scale(display_scale)(lower_part))\n",
|
|
"#!openscad -o lower_part.stl lower_part.scad"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"id": "b9b5f0fd",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"application/vnd.jupyter.widget-view+json": {
|
|
"model_id": "3791607ee3e84c9ca1943887389ae504",
|
|
"version_major": 2,
|
|
"version_minor": 0
|
|
},
|
|
"text/plain": [
|
|
"VBox(children=(HTML(value=''), Renderer(background='#cccc88', background_opacity=0.0, camera=PerspectiveCamera…"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"scad_render_to_file(scale(output_scale)(make_upper_part(True)), \"upper_part_holes.scad\")\n",
|
|
"r.render(scale(display_scale)(make_upper_part(True)))\n",
|
|
"!openscad -o upper_part_holes.stl upper_part_holes.scad"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"id": "b556b39b",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"application/vnd.jupyter.widget-view+json": {
|
|
"model_id": "bbb678c04348422da6ee48a7e4f6efd2",
|
|
"version_major": 2,
|
|
"version_minor": 0
|
|
},
|
|
"text/plain": [
|
|
"VBox(children=(HTML(value=''), Renderer(background='#cccc88', background_opacity=0.0, camera=PerspectiveCamera…"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"scad_render_to_file(scale(output_scale)(make_upper_part(False)), \"upper_part_no_holes.scad\")\n",
|
|
"r.render(scale(display_scale)(make_upper_part(False)))\n",
|
|
"!openscad -o upper_part_no_holes.stl upper_part_no_holes.scad"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "b2577f94",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": []
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "3e5d1f1e",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": []
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.8.10"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|