Model

bdc_motor.scad

Source: bdc_motor.scad
/*
 * Copyright 2019 Craig Ringer <ringerc@ringerc.id.au>
 * Copyright 2025 Cameron K. Brooks <cbrook49@uwo.ca; cambrooks3393@gmail.com>
 *
 * BSD Licensed
 *
 * A brushed DC hobby motor. The dimensions below are a "130 size" motor and are the defaults of hobby_dc_motor(),
 * which takes any of them as an argument of the same name:
 *
 *   use <bdc_motor.scad>
 *   hobby_dc_motor(motor_body_x = 25, motor_axle_length = 43);
 *
 * Features:
 * - Optionally generates the axle as a separate part, isolated by a tiny sleeve hollow.
 * - Optionally generates masking-out blocks for wiring, useful if subtracting this model from another design.
 *
 * Axle along x axis, protruding driven part of axle is "front", so power connectors etc are "back". The back face
 * of the motor body is at x = 0 and the body proceeds along +X; the rear protrusion and the back of the axle are at
 * negative x.
 */

zFite = $preview ? 0.1 : 0; // z-fighting avoidance for preview

/* [Render Control] */

// Render axle separately from motor body, isolated by a tiny sleeve hollow.
render_axle_separately = true;
// Clearance above body back area for wiring to mark out as a solid for subtractive use.
render_wiring_clearance_blocks = false;
// Opacity of motor body, in percent
body_alpha = 40; // [0:100]
// Opacity of trimmed areas, in percent
trim_alpha = 20; // [0:100]

/* [Body Parameters] */

// Length of motor excluding nylon back housing, the front protrusion and the protrusion from the back housing
motor_body_x = 20;
// Width of motor body (side to side)
motor_body_y = 20;
// Height of motor body before the flats are cut from the top and bottom
motor_body_z = 15;

/* [Front Protrusion] */

// Size of axle bearing/protrusion from front of body
motor_front_protrusion_x = 2;
// Diameter of front protrusion
motor_front_protrusion_diameter = 4.95;

/* [Axle] */

// Diameter of motor axle
motor_axle_diameter = 2;
// Length of axle protruding from back of motor
motor_axle_outset_length_back = 1;
// Length of motor axle
motor_axle_length = 38;

/* [Back Cover] */

// Nylon motor back part
motor_back_x = 5;
motor_back_tabs_z = 1.5;

// Width of flat top area projecting above motor back where wiring connects
motor_back_top_flat_y = 8.5;

// Nylon protrusion from nylon motor back
motor_back_protrusion_x = 2;
motor_back_protrusion_diameter = 10;
motor_back_protrusion_flat_bottom_zoff = 3.5;

// Length of flat area on bottom back protrusion. Checked against the diameter and offset above.
motor_back_protrusion_flat_bottom_width = 6;

// Back side notches
motor_back_side_notch_length_x = 6;
motor_back_side_notch_depth_y = 3;
motor_back_side_notch_height_z = 3;

/* [Back Slot] */

// Z offset to the bottom edge of the slot
motor_back_slot_zoff = 2;
// Height of slot
motor_back_slot_height_z = 1;
// Width of slot
motor_back_slot_width_y = 5.5;
// Depth of slot
motor_back_slot_depth_x = 1;

/* [Wiring Tabs] */

// Width of the clearance cubes
wiring_clearance_y = 4;
// Length of the clearance cubes
wiring_clearance_z = 4;

/* [Hidden] */

// Largest disagreement allowed between a measured dimension and the one derived from the others
measurement_tol = 0.2;

/* Dimensions derived from the others, for files that "use" this one. Each defaults to the 130 size motor. */

// Length of the motor without the axle: rear protrusion, back cover, body and front protrusion
function motor_length(motor_body_x = motor_body_x, motor_back_x = motor_back_x,
                      motor_front_protrusion_x = motor_front_protrusion_x,
                      motor_back_protrusion_x = motor_back_protrusion_x) =
    motor_back_protrusion_x + motor_back_x + motor_body_x + motor_front_protrusion_x;

function motor_axle_length(motor_axle_length = motor_axle_length) = motor_axle_length;
function motor_body_height(motor_body_z = motor_body_z) = motor_body_z;
// Body width, side to side across the round sides
function motor_body_width(motor_body_y = motor_body_y) = motor_body_y;
// [start, end] along x of the metal can, from the back cover's front face to the front protrusion
function motor_can_x(motor_body_x = motor_body_x, motor_back_x = motor_back_x) =
    [ motor_back_x, motor_back_x + motor_body_x ];
// The back cover is cut to the same height as the body
function motor_back_height(motor_body_z = motor_body_z) = motor_body_z;
function motor_axle_outset_back(motor_axle_outset_length_back = motor_axle_outset_length_back) =
    motor_axle_outset_length_back;

// Length of axle protruding from the front protrusion
function motor_axle_outset_front(motor_axle_length = motor_axle_length,
                                 motor_axle_outset_length_back = motor_axle_outset_length_back,
                                 motor_body_x = motor_body_x, motor_back_x = motor_back_x,
                                 motor_front_protrusion_x = motor_front_protrusion_x,
                                 motor_back_protrusion_x = motor_back_protrusion_x) =
    motor_axle_length - motor_axle_outset_length_back -
    motor_length(motor_body_x, motor_back_x, motor_front_protrusion_x, motor_back_protrusion_x);

// Distance from the back end of the axle to the back face of the motor body
function motor_back_start_x(motor_axle_outset_length_back = motor_axle_outset_length_back,
                            motor_back_protrusion_x = motor_back_protrusion_x) =
    motor_axle_outset_length_back + motor_back_protrusion_x;

function motor_side_notch_length(motor_back_side_notch_length_x = motor_back_side_notch_length_x) =
    motor_back_side_notch_length_x;

module hobby_dc_motor(
    render_axle_separately = render_axle_separately, render_wiring_clearance_blocks = render_wiring_clearance_blocks,
    body_alpha = body_alpha, trim_alpha = trim_alpha, motor_body_x = motor_body_x, motor_body_y = motor_body_y,
    motor_body_z = motor_body_z, motor_front_protrusion_x = motor_front_protrusion_x,
    motor_front_protrusion_diameter = motor_front_protrusion_diameter, motor_axle_diameter = motor_axle_diameter,
    motor_axle_outset_length_back = motor_axle_outset_length_back, motor_axle_length = motor_axle_length,
    motor_back_x = motor_back_x, motor_back_tabs_z = motor_back_tabs_z, motor_back_top_flat_y = motor_back_top_flat_y,
    motor_back_protrusion_x = motor_back_protrusion_x, motor_back_protrusion_diameter = motor_back_protrusion_diameter,
    motor_back_protrusion_flat_bottom_zoff = motor_back_protrusion_flat_bottom_zoff,
    motor_back_protrusion_flat_bottom_width = motor_back_protrusion_flat_bottom_width,
    motor_back_side_notch_length_x = motor_back_side_notch_length_x,
    motor_back_side_notch_depth_y = motor_back_side_notch_depth_y,
    motor_back_side_notch_height_z = motor_back_side_notch_height_z, motor_back_slot_zoff = motor_back_slot_zoff,
    motor_back_slot_height_z = motor_back_slot_height_z, motor_back_slot_width_y = motor_back_slot_width_y,
    motor_back_slot_depth_x = motor_back_slot_depth_x, wiring_clearance_y = wiring_clearance_y,
    wiring_clearance_z = wiring_clearance_z, measurement_tol = measurement_tol)
{
    // number of fragments for circles, unless the caller has set one
    $fn = $fn > 0 ? $fn : ($preview ? 64 : 128);

    // Height of the clearance cubes, from the front edge of the tabs to the back of the motor
    wiring_clearance_x = motor_back_protrusion_x + motor_back_x;

    clipping_color = "#FF0000";
    motor_axle_color = "#EEEEEE";
    motor_body_color = "#CCCCCC";
    clearance_area_color = "#CC00CC";
    body_opacity = body_alpha / 100;
    trim_opacity = trim_alpha / 100;

    // The axle reaches at least to the end of the front protrusion
    axle_outset_front = motor_axle_outset_front(motor_axle_length, motor_axle_outset_length_back, motor_body_x,
                                                motor_back_x, motor_front_protrusion_x, motor_back_protrusion_x);
    assert(axle_outset_front >= 0,
           str("motor_axle_length ", motor_axle_length, " is shorter than the motor and the back outset: ",
               motor_axle_length - axle_outset_front));

    // The slot lies inside the rear protrusion
    assert(motor_back_slot_zoff + motor_back_slot_height_z <= motor_back_protrusion_diameter / 2,
           str("the back slot ends ", motor_back_slot_zoff + motor_back_slot_height_z,
               " above the axis, outside a rear protrusion of radius ", motor_back_protrusion_diameter / 2));

    // The flat on the bottom of the rear protrusion is as wide as its diameter and offset make it
    flat_bottom_width = 2 * sqrt(pow(motor_back_protrusion_diameter / 2, 2) -
                                 pow(motor_body_z / 2 - motor_back_protrusion_flat_bottom_zoff, 2));
    assert(abs(flat_bottom_width - motor_back_protrusion_flat_bottom_width) <= measurement_tol,
           str("motor_back_protrusion_flat_bottom_width ", motor_back_protrusion_flat_bottom_width,
               " disagrees with the ", flat_bottom_width, " that the protrusion diameter and offset give"));

    module main_body()
    {
        trim_cube_thickness_main = (motor_body_y - motor_body_z) / 2;

        difference()
        {
            // Base motor body (main and back)
            color(motor_body_color, body_opacity) rotate([ 0, 90, 0 ])
                cylinder(d1 = motor_body_y, d2 = motor_body_y, h = motor_body_x + motor_back_x);

            color(clipping_color, trim_opacity) translate([ 0, -motor_body_y / 2, -motor_body_y / 2 ])
            {
                // Clip bottom, whole motor
                translate([ -zFite / 2, 0, 0 ])
                    cube([ motor_body_x + motor_back_x + zFite, motor_body_y, trim_cube_thickness_main ]);

                // Clip top, whole motor. Top back protrusion will be added in later.
                translate([ -zFite / 2, 0, motor_body_z + trim_cube_thickness_main ])
                    cube([ motor_body_x + motor_back_x + zFite, motor_body_y, trim_cube_thickness_main ]);
            };

            // Side back alignment slots/notches
            color(clipping_color, trim_opacity) for (side = [ -1, 1 ])
            {
                // Side notch: rectangular cut
                translate([
                    motor_back_side_notch_length_x / 2 - zFite / 2,
                    side * (-motor_body_y / 2 + motor_back_side_notch_depth_y / 4), 0
                ])
                    cube(
                        [
                            motor_back_side_notch_length_x + zFite, motor_back_side_notch_depth_y / 2,
                            motor_back_side_notch_height_z
                        ],
                        center = true);

                // Side notch: rounded bottom
                translate([
                    -zFite / 2,
                    side * (-motor_body_y / 2 + motor_back_side_notch_height_z - motor_back_side_notch_depth_y / 2), 0
                ]) rotate([ 0, 90, 0 ])
                    cylinder(d1 = motor_back_side_notch_height_z, d2 = motor_back_side_notch_height_z,
                             h = motor_back_side_notch_length_x + zFite);
            }
        }
    }

    module rear_cover()
    {
        difference()
        {
            mask_zoff = motor_body_z / 2 - motor_back_protrusion_flat_bottom_zoff;

            mask_height = motor_body_z / 2 - mask_zoff;
            // Rear protrusion base cylinder
            color(motor_body_color, body_opacity) rotate([ 0, 90, 0 ])
                cylinder(d1 = motor_back_protrusion_diameter, d2 = motor_back_protrusion_diameter,
                         h = motor_back_protrusion_x + zFite);

            // Rear protrusion bottom flat clipping
            color(clipping_color, trim_opacity)
                translate([ -zFite, -motor_back_protrusion_diameter / 2, -mask_zoff - mask_height ])
                    cube([ motor_back_protrusion_x, motor_back_protrusion_diameter, mask_height ], center = false);

            // Rear protrusion mid-top flat slot
            color(clipping_color, trim_opacity) translate([ -zFite, -motor_back_slot_width_y / 2, motor_back_slot_zoff ])
                cube([ motor_back_slot_depth_x + zFite, motor_back_slot_width_y, motor_back_slot_height_z ]);
        };
    }

    module front_protrusion()
    {
        rotate([ 0, 90, 0 ]) cylinder(d1 = motor_front_protrusion_diameter, d2 = motor_front_protrusion_diameter,
                                      h = motor_front_protrusion_x + zFite);
    }

    module axle(cut = false)
    {
        axle_cut_tol = cut ? 0.1 : 0;
        rotate([ 0, 90, 0 ]) cylinder(d = motor_axle_diameter + axle_cut_tol, h = motor_axle_length);
    }

    module wiring_tabs()
    {
        cube([ motor_back_x, motor_back_top_flat_y, motor_back_tabs_z ], center = false);
    }

    module wiring_clearance()
    {
        for (side = [ -1, 1 ])
        {
            translate([
                // Leave extra room behind motor for wires
                motor_axle_outset_length_back,
                //
                -wiring_clearance_y / 2 + side * (motor_back_top_flat_y / 2 + wiring_clearance_y / 2),
                motor_body_z / 2
            ]) cube([ wiring_clearance_x, wiring_clearance_y, wiring_clearance_z ]);
        }
    }

    // Motor body (main and back housing)
    difference()
    {
        union()
        {
            // Rear protrusion
            translate([ -motor_back_protrusion_x, 0, 0 ]) rear_cover();

            // Main motor body
            main_body();

            // Front protrusion/axle bearing
            translate([ motor_body_x + motor_back_x - zFite, 0, 0 ]) color(motor_body_color, body_opacity)
                front_protrusion();

            // Back top protrusion for wiring
            translate([ 0, -motor_back_top_flat_y / 2, motor_body_z / 2 ]) color(motor_body_color, body_opacity)
                wiring_tabs();
        };

        // Subtract axle shaft from whole motor
        if (render_axle_separately)
        {
            translate([ -motor_back_protrusion_x - zFite, 0, 0 ]) color(clipping_color, trim_opacity) axle(cut = true);
        }
    }; // end motor body difference

    // Axle
    color(motor_axle_color, body_opacity) translate([ -motor_axle_outset_length_back - motor_back_protrusion_x, 0, 0 ])
        axle();

    // Clearance area for motor wiring, if requested
    if (render_wiring_clearance_blocks)
    {
        translate([ -motor_axle_outset_length_back - motor_back_protrusion_x, 0, 0 ])
            color(clearance_area_color, body_opacity) wiring_clearance();
    }
};

hobby_dc_motor();

bdc_motor.scad on GitHub


This site uses Just the Docs, a documentation theme for Jekyll.