swimtracker-firmware/hardware/case/case_solidpython.ipynb

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
}