{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import cadquery as cq\n", "from jupyter_cadquery import (\n", " open_viewer, show,\n", " set_defaults, get_defaults\n", ")\n", "from cadquery_massembly import Mate, MAssembly, relocate\n", "\n", "cv = open_viewer(\"Hexapod\", cad_width=800, height=600, theme=\"light\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "set_defaults(axes=False, axes0=True, mate_scale=5, transparent=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Hexapod " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![2-hexapod.png](2-hexapod.png)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "horizontal_angle = 25\n", "\n", "def intervals(count):\n", " r = [ min(180, (90 + i*(360 // count)) % 360) for i in range(count)]\n", " return r \n", "\n", "def times(end, count):\n", " return np.linspace(0, end, count+1)\n", " \n", "def vertical(count, end, offset, reverse):\n", " ints = intervals(count)\n", " heights = [round(35 * np.sin(np.deg2rad(x)) - 15, 1) for x in ints]\n", " heights.append(heights[0])\n", " return times(end, count), heights[offset:] + heights[1:offset+1]\n", "\n", "def horizontal(end, reverse):\n", " factor = 1 if reverse else -1\n", " return times(end, 4), [0, factor * horizontal_angle, 0, -factor * horizontal_angle, 0]\n", "\n", "print(\"Leg group 1 (transparent)\")\n", "print(\"horizontal movement \", horizontal(4, True))\n", "print(\"vertical heights (left) \", vertical(8, 4, 0, True))\n", "print(\"vertical heights (right)\", vertical(8, 4, 0, False))\n", "\n", "print(\"\\nLeg group 1 (filled)\")\n", "print(\"horizontal movement\", horizontal(4, False))\n", "print(\"vertical heights (left) \", vertical(8, 4, 4, True))\n", "print(\"vertical heights (right)\", vertical(8, 4, 4, False))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Assembly" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Parts" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "thickness = 2\n", "height = 40\n", "width = 65\n", "length = 100\n", "diam = 4\n", "tol = 0.05" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def create_base():\n", " x1, x2 = 0.63, 0.87\n", " base_holes = {\n", " \"right_front\": (-x1*width, -x1*length), \"right_middle\": (-x2*width, 0), \"right_back\": ( -x1*width, x1*length ),\n", " \"left_front\": ( x1*width, -x1*length), \"left_middle\": ( x2*width, 0), \"left_back\": ( x1*width, x1*length ),\n", " }\n", " stand_holes = {\"front_stand\": (0, -0.75 * length), \"back_stand\": (0, 0.8 * length)}\n", "\n", " workplane = cq.Workplane()\n", "\n", " base = (workplane\n", " .ellipseArc(width, length, 295, 245, startAtCurrent=False).close()\n", " .pushPoints(list(base_holes.values())).circle(diam / 2 + tol)\n", " .moveTo(*stand_holes[\"back_stand\" ]).rect(width / 2 + 2 * tol, thickness + 2 * tol)\n", " .moveTo(*stand_holes[\"front_stand\"]).rect(width / 2 + 2 * tol, thickness + 2 * tol)\n", " .extrude(thickness)\n", " )\n", " base\n", "\n", "\n", " base.faces(\"Z\").tag(\"top\")\n", "\n", " for name, hole in base_holes.items():\n", " base.faces(\"Z\").edges(cq.NearestToPointSelector(upper_leg_hole)).tag(\"top\")\n", " upper_leg.faces(\"Z\").edges(cq.NearestToPointSelector(lower_leg_hole)).tag(\"top\"),\n", " lower_leg.faces(\"