commit 6cc0cc496c94f3795b6271a599dfbd41c3467016 Author: Lauri Võsandi Date: Mon May 6 19:53:11 2019 +0300 Initial commit diff --git a/sumorobot-frame.scad b/sumorobot-frame.scad new file mode 100644 index 0000000..17cdcf3 --- /dev/null +++ b/sumorobot-frame.scad @@ -0,0 +1,425 @@ +/* Error tolerance for cutouts */ +T = 0.2; + +/* Arc smoothness */ +R = 100; + +/* PCB dimensions */ +PCB_WIDTH = 66.5; +PCB_DEPTH = 66.5; +PCB_THICKNESS = 1.6; +PCB_OFFSET = 6; + +/* Robot dimensions */ +THICKNESS = 3; +WIDTH = 100; +HEIGHT = 90; +DEPTH = 100; +OFFSET = 34; +TILT = -8; + +/* Ultrasonic sensor parameters */ +ULTRASONIC_SENSOR_PLACEMENT = 47; +ULTRASONIC_SENSOR_SPAN = 26.5; +ULTRASONIC_SENSOR_HOLE = 16; + +/* Line sensor parameters */ +LINE_SENSOR_PLACEMENT = 13.5; +LINE_SENSOR_HOLES = 3; +LINE_SENSOR_SPAN = 38; + +/* How far from eachother servo mount surfaces are placed */ +SERVO_AXLE_LENGTH = 58; + +COVER_WIDTH = 70; +COVER_HEIGHT = 76; + +/* Servo parameters */ +SERVO_MOUNT_PLACEMENT = 65; +SERVO_MOUNT_OFFSET = 33.5; + +/* Magnet parameters */ +MAGNET_HEIGHT = 0.8; +MAGNET_DIAMETER = 5; + +/* Show placeholders for battery, wheels, PCB, etc */ +DEBUG = false; + +/* Helper function for mirror-copying object */ +module mirror_copy() { + children(); + mirror() { + children(); + } +} + +/* Mount holes for servos */ +module mount_hole() { + cylinder(h = 100, d = LINE_SENSOR_HOLES + T, $fn = R); +} + +/* Standard servo cutout helper */ +module servo_cutout() { + translate([-34.5, 5, 0]) mount_hole(); + translate([-34.5, -5, 0]) mount_hole(); + translate([15, 5, 0]) mount_hole(); + translate([15, -5, 0]) mount_hole(); + translate([-31, -10, 0]) cube([40 + T * 2 + 2, 20 + T * 2, 100]); +} + +module face() { + difference() { + union() { + /* Front face */ + cube([WIDTH / 2, HEIGHT * 2, THICKNESS]); + + /* Ultrasonic sensor mount */ + rotate([TILT, 0, 0]) { + translate([ULTRASONIC_SENSOR_SPAN / 2, ULTRASONIC_SENSOR_PLACEMENT, 0]) { + cylinder(h = 20, d = ULTRASONIC_SENSOR_HOLE + THICKNESS, $fn = R); + } + } + } + + /* Line following sensor mounting holes */ + translate([0, LINE_SENSOR_PLACEMENT, -T]) { + translate([LINE_SENSOR_SPAN, 0, 0]) { + cylinder(h = THICKNESS + T * 2, d2 = LINE_SENSOR_HOLES + T, d1 = LINE_SENSOR_HOLES * 2 + T, $fn = R); + } + cylinder(h = THICKNESS + T * 2, d2 = LINE_SENSOR_HOLES + T, d1 = LINE_SENSOR_HOLES * 2 + T, $fn = R); + } + + + /* Ultrasonic sensor cutout */ + rotate([TILT, 0, 0]) { + translate([0, ULTRASONIC_SENSOR_PLACEMENT, 0]) { + translate([ULTRASONIC_SENSOR_SPAN / 2, 0, -1]) { + cylinder(h = 100, d = ULTRASONIC_SENSOR_HOLE + T, $fn = R); + } + + translate([0, 0, 15]) { + cube([ULTRASONIC_SENSOR_SPAN / 2, ULTRASONIC_SENSOR_SPAN / 2, 30]); + } + } + } + } +} + +module frame() { + /* Front face to top face support arcs */ + rotate([0, 90, 0]) { + translate([-90, 0, -WIDTH / 2]) { + difference() { + cylinder(d = 300, h = T + WIDTH/2 - COVER_WIDTH/2, $fn = R); + translate([0, 0, -THICKNESS]) + cylinder(d = 176, h = WIDTH-COVER_WIDTH, $fn = R); + + /* Clear out line sensor holes */ + cube([200, 30, 20]); + translate([-200, -200, -1]) { + cube([200, 400, 20]); + } + } + } + } + + difference() { + translate([-COVER_WIDTH / 2, HEIGHT - OFFSET, 0]) { + /* PCB compartment walls */ + cube([THICKNESS, OFFSET, DEPTH]); + + /* PCB rails */ + translate([0, OFFSET - PCB_OFFSET - THICKNESS * 3, 0]) { + cube([6, PCB_OFFSET + THICKNESS * 3, DEPTH]); + + } + } + + /* PCB cutout */ + translate([-PCB_WIDTH / 2, HEIGHT - 9, DEPTH - PCB_DEPTH - THICKNESS + T]) { + cube([PCB_WIDTH + T, PCB_THICKNESS + T, PCB_DEPTH]); + translate([0, -PCB_THICKNESS, -2]) { + cube([PCB_WIDTH + T, PCB_THICKNESS + T, PCB_DEPTH]); + } + } + + } + + /* Servo mounting walls */ + translate([-SERVO_AXLE_LENGTH / 2, 0, 0]) { + cube([THICKNESS, HEIGHT - OFFSET, DEPTH]); + } + + rotate([90, 0, 0]) { + /* Bottom face */ + translate([0, 0, -HEIGHT + COVER_HEIGHT]) { + cube([SERVO_AXLE_LENGTH / 2, DEPTH, THICKNESS]); + } + + /* Bottom support columnns */ + translate([SERVO_AXLE_LENGTH / 2 - 12, 0, -HEIGHT + COVER_HEIGHT - 4]) { + cube([10, DEPTH, 18]); + } + + + /* Battery compartment separator */ + translate([0, 0, -HEIGHT + OFFSET]) { + difference() { + cube([COVER_WIDTH / 2, DEPTH, THICKNESS]); + translate([0, 0, -T]) { + cube([SERVO_AXLE_LENGTH / 2, 20, THICKNESS + T * 2]); + translate([0, 20, 0]) { + /* Arc to ease 3D printing */ + cylinder(h = THICKNESS * 2, d = SERVO_AXLE_LENGTH - THICKNESS * 2, $fn = R); + translate([0, 80, 0]) + cylinder(h = THICKNESS * 2, d = SERVO_AXLE_LENGTH - THICKNESS * 2, $fn = R); + } + } + } + } + } + + /* Top face */ + translate([0, HEIGHT - THICKNESS, 0]) { + cube([WIDTH / 2, THICKNESS, DEPTH]); + + } +} + + +module half() { + difference() { + union() { + face(); + difference() { + rotate([TILT, 0, 0]) { + frame(); + } + + /* Line following sensor wires */ + translate([0, 32, THICKNESS]) { + rotate([0, -90, 0]) { + cylinder(d = 26, h = 30, $fn = R); + } + rotate([90, 0, 0]) { + cylinder(d = 26, h = 100, $fn = R); + } + + } + + rotate([TILT]) { + rotate([0, -90, 0]) { + /* Bottom arc */ + translate([50, -86, -50]) { + cylinder(d = 195, h = 100, $fn = R); + } + + /* Servo mount */ + translate([SERVO_MOUNT_PLACEMENT, SERVO_MOUNT_OFFSET, 0]) { + servo_cutout(); + } + } + } + + } + } + + /* Front face cutoff */ + translate([-100, -100, -100]) { + cube([200, 300, 100]); + } + + /* Bottom face cutoff */ + translate([-100, -100, -100]) { + cube([300, 100, 300]); + } + + /* Top face cutoff */ + rotate([TILT, 0, 0]) { + translate([-100, HEIGHT, -100]) { + cube([200, 200, 200]); + } + + translate([-COVER_WIDTH / 2 - T, HEIGHT - COVER_HEIGHT - THICKNESS, DEPTH - THICKNESS]) { + cube([COVER_WIDTH + T, 200, 200]); + } + + + } + } +} + +module magnet_hole() { + cylinder(d = MAGNET_DIAMETER + T, h = MAGNET_HEIGHT + T, $fn = R); +} + +module magnet_holes() { + mirror_copy() { + /* Top holes */ + translate([+COVER_WIDTH / 2 - MAGNET_DIAMETER / 2 - 0.5, HEIGHT - 3, -MAGNET_HEIGHT]) { + magnet_hole(); + } + /* Bottom holes */ + translate([SERVO_AXLE_LENGTH / 2 - MAGNET_DIAMETER / 2 - 0.5, HEIGHT - COVER_HEIGHT + MAGNET_DIAMETER / 2 - THICKNESS + 0.5, -MAGNET_HEIGHT]) { + magnet_hole(); + } + } +} + +module sumorobot() { + difference() { + mirror_copy() { + half(); + } + rotate([TILT, 0, 0]) { + translate([0, 0, DEPTH - THICKNESS]) { + magnet_holes(); + } + } + } +} + + +module cover() { + translate([0, 100, 0]) { + difference() { + union() { + translate([-27, COVER_HEIGHT-20, 0]) + cube([35,12,THICKNESS*2]); + + mirror_copy() { + // Battery/servo compartment cover + translate([0, 0, 0]) { + cube([SERVO_AXLE_LENGTH / 2, COVER_HEIGHT, THICKNESS]); + } + + // PCB compartment cover + translate([0, COVER_HEIGHT - OFFSET, 0]) { + cube([COVER_WIDTH / 2, OFFSET + THICKNESS, THICKNESS]); + } + + // PCB locking mechanism + translate([PCB_WIDTH/2-T-6, COVER_HEIGHT-6, 0]) { + cube([6, PCB_THICKNESS-T, THICKNESS+3*PCB_THICKNESS]); + + cube([PCB_THICKNESS, 5, THICKNESS+3*PCB_THICKNESS]); + } + } + } + translate([0, COVER_HEIGHT - HEIGHT + THICKNESS, THICKNESS]) { + magnet_holes(); + } + translate([-COVER_WIDTH/2+THICKNESS-0.5, COVER_HEIGHT+THICKNESS-0.5-PCB_THICKNESS, -T]) { + translate([10.7, -13.1, 0]) { + cylinder(d2=5, d1=5+THICKNESS, h=THICKNESS+T*2, $fn=R); + cylinder(d=5, h=10, $fn=R); + + } + translate([36.2, -13.1, 0]) cylinder(d=5, h=THICKNESS*3+T*2, $fn=R); + translate([17.8-T*2, -19.46, 0]) cube([12.1+T*4, 10.5+T*4, 20]); + } + + + + } + } +} + +module plow_hole() { + translate([0, 0, -T]) + cylinder(d1=LINE_SENSOR_HOLES+T, d2=LINE_SENSOR_HOLES*3, h=THICKNESS+T+T, $fn=R); + translate([0, 0, THICKNESS]) { + cylinder(d=LINE_SENSOR_HOLES*3, h=WIDTH, $fn=R); + } +} + +module plow() { + translate([0, -40, 0]) { + mirror_copy() { + difference() { + rotate([TILT, 0, 0]) { + cube([WIDTH/2, LINE_SENSOR_PLACEMENT*2-6, 50]); + } + + rotate([-TILT, 0, 0]) + translate([-T, LINE_SENSOR_PLACEMENT*2-6, -6]) + cube([100, 100, 100]); + translate([-T, 0, -100]) { + cube([100, 100, 100]); + } + + translate([0, LINE_SENSOR_PLACEMENT-3]) { + translate([LINE_SENSOR_SPAN, 0]) { + plow_hole(); + } + plow_hole(); + } + translate([0, -1, 50]) { + rotate([-90, 0, 0]) { + cylinder(d=WIDTH-10, h=50, $fn=R); + } + } + } + } + } +} + +sumorobot(); +cover(); +plow(); + +if (DEBUG) { + color([1, 0, 0]) { + rotate([TILT, 0, 0]) { + rotate([90, 0, 0]) { + /* PCB board mockup */ + translate([0, 0, -HEIGHT + PCB_OFFSET + T]) { + translate([-PCB_WIDTH / 2, DEPTH - PCB_DEPTH, 0]) { + cube([PCB_WIDTH, PCB_DEPTH + 5, 1.6]); + } + + translate([-PCB_WIDTH / 2 + 5, DEPTH - PCB_DEPTH, 0]) { + cube([PCB_WIDTH - 10, PCB_DEPTH - 5, 20]); + } + } + + /* Battery mockup */ + translate([-25, 30, -24]) { + translate([0, 0, 0]) { + cube([50, 60, 5.5]); + } + translate([10, 0, 0]) { + cube([30, 50, 10]); + } + } + } + } + + translate([WIDTH / 2 + 28 / 2, HEIGHT - 47, 0]) { + cylinder(h = 12, d = 15, $fn = R); + } + + /* Wheel mockups */ + rotate([TILT]) { + rotate([0, -90, 0]) { + translate([SERVO_MOUNT_PLACEMENT, SERVO_MOUNT_OFFSET, SERVO_AXLE_LENGTH/2 + 10]) { + difference() { + cylinder(d=70, h=11); + cylinder(d=3, h=12); + } + } + } + } + + /* Line sensor mockups */ + difference() { + translate([0, LINE_SENSOR_PLACEMENT - 5.2, THICKNESS]) { + translate([WIDTH / 2 - (+12 + 8.9), 0, 0]) cube([17.8, 15.2, 5.2]); + translate([-8.9, 0, 0]) cube([17.8, 15.2, 5.2]); + translate([-WIDTH / 2 + 12 - 8.9, 0, 0]) cube([17.8, 15.2, 5.2]); + } + cylinder(d = 3, h = 20, $fn = R); + translate([38, 0, 0]) cylinder(d = 3, h = 20, $fn = R); + } + } +} diff --git a/sumorobot-remote.scad b/sumorobot-remote.scad new file mode 100644 index 0000000..1cadd52 --- /dev/null +++ b/sumorobot-remote.scad @@ -0,0 +1,179 @@ +WIDTH = 114; +HEIGHT = 63; +DEPTH = 30; + +R = 30; +THICKNESS = 2; + +BORDER_RADIUS = 4; +JOYSTICK_AXIS_DIAMETER = 31; +JOYSTICK_TO_BUTTONS = 45.72; +BUTTON_DIAMETER = 11.5; +T = 0.2; +BUTTON_PLACEMENT_DIAMETER = 22.86; +BUTTON_PLACEMENT_LEFT = WIDTH / 2 - JOYSTICK_TO_BUTTONS / 2; +JOYSTICK_LEFT = WIDTH / 2 + JOYSTICK_TO_BUTTONS / 2; +JOYSTICK_TOP = HEIGHT / 2; +BUTTON_SINK = 13.5; + +TRAY_WIDTH = 35; +TRAY_HEIGHT = 52; +TRAY_DEPTH = 6; +TRAY_THICKNESS = 1; + + +SWITCH_POSITION = WIDTH - 27; +SWITCH_HEIGHT = 12.7; +SWITCH_WIDTH = 19.3; + +SCREW_HOLE = 6.3; + +STANDOFF_H = 20; +STANDOFF_D2 = 4.65; +STANDOFF_D = STANDOFF_D2 / 0.866; + +module box(width, height, depth, h1 = STANDOFF_D, h2 = STANDOFF_D, hd = STANDOFF_H, hr=6) { + difference() { + translate([0, 0, -THICKNESS]) { + // Bottom + translate([-BORDER_RADIUS, 0, 0]) cube([width + BORDER_RADIUS * 2, HEIGHT, THICKNESS]); + translate([0, -BORDER_RADIUS, 0]) cube([width, height + BORDER_RADIUS * 2, THICKNESS]); + + // Walls + translate([0, -BORDER_RADIUS, 0]) cube([width, THICKNESS, depth + THICKNESS]); + translate([-BORDER_RADIUS, 0, 0]) cube([THICKNESS, height, depth + THICKNESS]); + translate([0, height + BORDER_RADIUS - THICKNESS, 0]) cube([width, THICKNESS, depth + THICKNESS]); + translate([width + BORDER_RADIUS - THICKNESS, 0, 0]) cube([THICKNESS, height, depth + THICKNESS]); + + + // Screw hole cylinders + cylinder(r = BORDER_RADIUS, h = depth + THICKNESS, $fn = R); + translate([WIDTH, 0, 0]) cylinder(r = BORDER_RADIUS, h = depth + THICKNESS, $fn = R); + translate([0, HEIGHT, 0]) cylinder(r = BORDER_RADIUS, h = depth + THICKNESS, $fn = R); + translate([WIDTH, HEIGHT, 0]) cylinder(r = BORDER_RADIUS, h = depth + THICKNESS, $fn = R); + } + + // Screw hole + translate([0, 0, depth - hd - T]) { + cylinder(d1 = h1+T, d2 = h2+T, h = hd+T+T, $fn = hr); + translate([WIDTH, 0, 0]) cylinder(d1 = h1+T, d2 = h2+T, h = hd+T+T, $fn = hr); + translate([0, HEIGHT, 0]) cylinder(d1 = h1+T, d2 = h2+T, h = hd+T+T, $fn = hr); + translate([WIDTH, HEIGHT, 0]) cylinder(d1 = h1+T, d2 = h2+T, h = hd+T+T, $fn = hr); + + } + } +} + +// Cover +translate([0, -THICKNESS - BORDER_RADIUS * 2, 0]) { + mirror([0, 1, 0]) { + difference() { + box(WIDTH, HEIGHT, 0, h1 = 5.4, h2 = 2.8, hr=R, hd = THICKNESS); + translate([WIDTH/2-5, -BORDER_RADIUS+THICKNESS+T+1, -THICKNESS-T]) + cube([10, 4, 10]); + } + + // Switch fixer + translate([SWITCH_POSITION + T, -BORDER_RADIUS, 0]) { + cube([SWITCH_WIDTH - T - T, BORDER_RADIUS, DEPTH - SWITCH_HEIGHT - T]); + } + + // Charger mount + translate([WIDTH/2-19/2-3, -BORDER_RADIUS+THICKNESS+T, 0]) { + difference() { + cube([19+3+3, 7, DEPTH - SWITCH_HEIGHT - T]); + translate([+3, 0, 0]) + cube([19, 3, 20]); + + translate([7.5, 0, 0]) + cube([10, 5, 20]); + } + } + + } +} + + +module screw_hole(dia=SCREW_HOLE) { + difference() { + cylinder(h = 11, d = 8, $fn = R); + translate([0, 0, TRAY_DEPTH]) + cylinder(h = TRAY_DEPTH + T, d = dia, $fn = R); + + } +} + +module button() { + cylinder(d1 = BUTTON_DIAMETER + THICKNESS * 2 + T, d2 = BUTTON_DIAMETER + T, h = THICKNESS + T * 2, $fn = R); +} + +module case () { + difference() { + union() { + box(WIDTH, HEIGHT, DEPTH); + + + // Switch holder + translate([SWITCH_POSITION - 5, -BORDER_RADIUS + T + T, 0]) { + cube([SWITCH_WIDTH + 10, BORDER_RADIUS, DEPTH]); + translate([-85+6, 0,0 ]) + cube([85, 5,3.5]); + } + + + + + } + + // Switch cutout + translate([SWITCH_POSITION, -BORDER_RADIUS - T, 0]) { + cube([SWITCH_WIDTH, THICKNESS, HEIGHT]); + translate([-1, THICKNESS, 0]) + cube([SWITCH_WIDTH + 2, BORDER_RADIUS, HEIGHT]); + } + + + union() { + + translate([JOYSTICK_LEFT, JOYSTICK_TOP, 5]) { + sphere(JOYSTICK_AXIS_DIAMETER / 2); + } + + translate([BUTTON_PLACEMENT_LEFT, JOYSTICK_TOP, -THICKNESS]) { + translate([BUTTON_PLACEMENT_DIAMETER / 2, 0, -T]) button(); + translate([0, BUTTON_PLACEMENT_DIAMETER / 2, -T]) button(); + translate([-BUTTON_PLACEMENT_DIAMETER / 2, 0, -T]) button(); + translate([0, -BUTTON_PLACEMENT_DIAMETER / 2, -T]) button(); + } + } + + + + + } + + + /* PCB mounting holes */ + translate([BUTTON_PLACEMENT_LEFT, JOYSTICK_TOP, 0]) { + translate([-18.9, BUTTON_PLACEMENT_DIAMETER / 2, 0]) { + screw_hole(1.9); + translate([0, -28, 0]) { + screw_hole(1.9); + } + } + } + + + translate([BUTTON_PLACEMENT_LEFT + JOYSTICK_TO_BUTTONS, JOYSTICK_TOP, 0]) { + + translate([+12.2 + 1.5, +24.7 + 1.5, 0]) { + screw_hole(1.9); + } + + } + +} + + + +case ();