Example #1
0
def bogie_pivot_up_y_equation(arm_length, bogie_pivot_up_y):
    up_angle = get_arm_angle(arm_length, bogie_pivot_up_y)
    down_angle = up_angle - travel_angle
    travel = get_arm_travel(arm_length, down_angle, bogie_pivot_up_y)

    neutral_angle = get_arm_angle(
        arm_length, bogie_pivot_up_y - (1 - suspension_sag) * travel)

    bogie_pivot_up_point = Vector(math.cos(up_angle),
                                  math.sin(up_angle)) * arm_length

    left_angle = (up_angle - neutral_angle) - bogie_swing_angle
    left_wheel_position = bogie_pivot_up_point + get_bogie_wheel_position(
        left_angle, -1)

    dist_left = util.point_to_line_distance(left_wheel_position,
                                            spring_up_point,
                                            spring_anchor_point)
    dist_right = abs(bogie_pivot_up_point -
                     (spring_down_point + Vector(suspension_spacing, 0)))

    ret1 = dist_left - wheel_diameter / 2 - vitamins.spring.diameter / 2 - wheel_clearance
    #ret2 = dist_right - math.hypot(bogie_wheel_spacing / 2, bogie_pivot_z) - wheel_diameter / 2 - arm_thickness / 2 - wheel_clearance

    return ret1
Example #2
0
def arm_generator(thickness, pivot_thickness, width, spring_point_width,
                  arm_length, spring_arm_length, spring_angle_offset,
                  cone_height, wheel_diameter, wheel_clearance,
                  pivot_hole_diameter, wheel_bearing, wheel_screw,
                  spring_screw):

    cone_upper_diameter = wheel_bearing.id + 2 * wheel_bearing.shoulder_size

    spring_point = Vector.polar(spring_arm_length, spring_angle_offset)

    p1, _ = util.outer_tangent(Vector(0, 0), (pivot_thickness - thickness) / 2,
                               Vector(arm_length, 0), 0)
    _, p2 = util.outer_tangent(spring_point, 0, Vector(0, 0),
                               (pivot_thickness - thickness) / 2)

    outline = polygon2d([(p1.x, p1.y),
                         (arm_length, 0),
                         (spring_point.x, spring_point.y),
                         (p2.x, p2.y)]) \
        .offset(thickness / 2)
    outline += circle(d=pivot_thickness)

    arm = outline \
        .extruded(spring_point_width, symmetrical=False)

    arm -= rectangle(wheel_diameter, 2 * spring_point_width) \
        .translated_y(spring_point_width + arm_width + wheel_clearance) \
        .offset(wheel_clearance) \
        .revolved() \
        .rotated_x(90) \
        .translated_x(arm_length)

    cone = tools.cone(height=cone_height,
                      upper_diameter=cone_upper_diameter,
                      lower_diameter=(cone_upper_diameter + thickness) / 2 + cone_height,
                      base_height=width) \
        .translated_x(arm_length)
    arm += cone & outline.extruded(float("inf"))

    arm -= cylinder(d=pivot_hole_diameter, h=float("inf"))

    arm -= tools.screw_hole_with_nut_pocket(wheel_screw) \
        .translated_x(arm_length)

    arm -= tools.screw_hole_with_nut_pocket(spring_screw) \
        .translated(*spring_point)

    return arm
Example #3
0
def spring_arm_length_equation(spring_arm_length):
    """ Equation describing spring location relative to the pivot. """
    spring_anchor_point = get_spring_anchor_point(spring_arm_length)
    travel_angle = get_travel_angle(spring_arm_length, spring_anchor_point)
    spring_down_point = get_spring_point(spring_arm_length, travel_angle)

    spring_axis_to_pivot_point = util.point_to_line_distance(
        Vector(0, 0), spring_anchor_point, spring_down_point)

    return spring_axis_to_pivot_point - (
        arm_thickness / 2 + vitamins.spring.diameter / 2 + arm_clearance)
Example #4
0
def get_wheel_force(arm_length, up_angle, angle):
    """ Return residual force on a group of wheels. """
    spring_point = get_spring_point(spring_arm_length, up_angle - angle)
    length = abs(spring_point - spring_anchor_point.flattened())
    spring_force = vitamins.spring.force(length)

    torque = spring_force * util.point_to_line_distance(
        Vector(0, 0), spring_anchor_point.flattened(), spring_point)
    wheel_force = torque / (arm_length * math.cos(angle))

    return wheel_force - parameters.design_weight / bogie_count
Example #5
0
def outer_tangent(p1, r1, p2, r2):
    """ Return a pair of points on circles (p1, r1) and (p2, r2) that form
    a line tangent to both of these circles.
    This is always an outer tangent and which one of the two outer tangents is returned
    is determined by the order of the parameters (it's the one to the left from
    line segment p1, p2). """

    dp = p2 - p1
    dr = r2 - r1
    dp2 = dp.abs_squared()
    tmp = Vector(math.sqrt(dp2 - dr * dr), dr)
    direction = Vector(perpendicular(dp).dot(tmp), -dp.dot(tmp)) / dp2

    ret1 = p1 + direction * r1
    ret2 = p2 + direction * r2

    dret = ret2 - ret1
    assert abs(ret1 - p1) == Approx(r1)
    assert abs(ret2 - p2) == Approx(r2)
    assert dret.dot(ret1 - p1) == Approx(0)
    assert dret.dot(ret2 - p2) == Approx(0)

    return (ret1, ret2)
Example #6
0
def tensioner_generator(right,
                        arm_angle=(arm_angle_back + arm_angle_front) / 2):
    spring_point = Vector.polar(
        spring_arm_length, arm_angle + spring_angle_offset) + pivot_position

    v = spring_point.flattened() - spring_anchor_point.flattened()
    length = abs(v)

    spring_degrees = 90 - math.degrees(math.atan2(v.y, v.x))
    spring = vitamins.spring(length)

    if right:
        arm = arm_right
        multiplier = 1
    else:
        arm = arm_left.rotated_y(180)
        multiplier = -1

    arm_angle = -arm_angle

    asm = codecad.assembly("tensioner_assembly_" + ("right" if right else "left"),
                           [arm \
                                .rotated_x(-90) \
                                .rotated_y(180) \
                                .rotated_y(arm_angle) \
                                .translated(pivot_position.x, pivot_position.z, pivot_position.y),
                            wheel_assembly \
                                .translated_y(-arm_width - wheel_clearance) \
                                .rotated_z(90 + 90 * multiplier) \
                                .translated_x(arm_length) \
                                .rotated_y(arm_angle) \
                                .translated(pivot_position.x, pivot_position.z, pivot_position.y),
                            spring \
                                .rotated_y(spring_degrees) \
                                .translated(spring_anchor_point.x,
                                            multiplier * (spring_anchor_point.z + vitamins.spring.top_mount_thickness / 2),
                                            spring_anchor_point.y),
                            wheel_screw,
                            wheel_screw.lock_nut,
                            spring_screw,
                            spring_screw.lock_nut,
                            vitamins.shoulder_screw,
                            vitamins.shoulder_screw.lock_nut,
                            vitamins.m5x20_screw,
                            vitamins.m5x20_screw.lock_nut])

    return asm
Example #7
0
              inner_bearing_height) / 2
# Max length so that the pivot is still completely hidden by the wheel
arm_pivot_thickness = 2 * (wheel_diameter / 2 - arm_length - wheel_clearance)


def spring_arm_length_equation(spring_arm_length):
    return arm_length**2 + spring_arm_length**2 - 2 * arm_length * spring_arm_length * math.cos(math.radians(spring_angle_offset)) - \
           (wheel_diameter / 2 + wheel_clearance + vitamins.spring.bottom_mount_od / 2)**2


spring_arm_length = scipy.optimize.brentq(spring_arm_length_equation, 0,
                                          2 * wheel_diameter)

pivot_to_spring_anchor = spring_arm_length + vitamins.spring.length - vitamins.spring.travel - spring_inversion_safety_distance
pivot_y = wheel_base_y + arm_length
pivot_position = Vector(0, pivot_y)
pivot_to_spring_anchor_angle = -math.degrees(
    math.asin((pivot_y - spring_anchor_y) / pivot_to_spring_anchor))

spring_anchor_point = Vector(
    math.sqrt(pivot_to_spring_anchor**2 - (pivot_y - spring_anchor_y)**2),
    spring_anchor_y)
to_suspension_pivot = spring_anchor_point.x + suspension.arm_pivot_thickness / 2 + vitamins.spring.top_mount_od / 2 + suspension.arm_clearance


def get_arm_angle(spring_length):
    return pivot_to_spring_anchor_angle - \
           math.degrees(math.acos((spring_arm_length**2 + pivot_to_spring_anchor**2 - spring_length**2) /
                                  (2 * spring_arm_length * pivot_to_spring_anchor))) - \
           spring_angle_offset
Example #8
0
import codecad
from codecad.shapes import *
from codecad.util import Vector
import parametric

import parameters
import tools
import vitamins
import tensioner
import suspension
import drive_sprocket
import track
import transmission

suspension_pivot_y = 30
tensioner_position = tensioner.pivot_position + Vector(0, suspension_pivot_y)
bogie_positions = [
    Vector(i * suspension.suspension_spacing + tensioner.to_suspension_pivot,
           suspension_pivot_y)
    #for i in range(1)]
    for i in range(suspension.bogie_count // 2)
]
drive_sprocket_position = Vector(
    bogie_positions[-1].x + drive_sprocket.to_suspension_pivot,
    suspension_pivot_y)

track_clearance = 5  # Distance between track and hull


def top_back_cross_frame_member(angle, size, wall_thickness):
    """ Return a 2D shape with the profile of the frame member going across the tank on the top back side """
Example #9
0
def perpendicular(v):
    """ Perpendicular vector to v (2D only) """
    v = v.flattened()
    return Vector(v.y, -v.x)
Example #10
0
def get_spring_anchor_point(spring_arm_length):
    """ Return the spring anchor point coordinates in 2D relative to arm pivot as codecad Vector.
    Spring is placed to be at right angle to the arm at full compression. """
    return get_spring_point(spring_arm_length, 0) + \
        Vector(-math.sin(spring_up_angle), math.cos(spring_up_angle)) * (vitamins.spring.length - vitamins.spring.travel)
Example #11
0
def get_spring_point(spring_arm_length, angle):
    """ Return coordinates of the spring attachment to the arm if the spring is at given angle
    (angle is between 0 (up position) and travel_angle) """
    return Vector(math.cos(spring_up_angle - angle),
                  math.sin(spring_up_angle - angle)) * spring_arm_length
Example #12
0
def arm_generator(thickness, pivot_thickness, width, bogie_side_width,
                  arm_length, spring_arm_length, arm_neutral_angle,
                  arm_up_angle, knee_height, knee_angle, pivot_mount_diameter,
                  pivot_mount_height, pivot_mount_screw_head_diameter,
                  pivot_mount_screw_head_countersink, spring_mount_diameter,
                  spring_mount_height, bogie_pivot_mount_diameter, thin_wall,
                  thick_wall, hole_blinding_layer_height):
    spring_point_angle = spring_up_angle - arm_up_angle
    bogie_pivot = (arm_length, 0)
    spring_point = (spring_arm_length * math.cos(spring_point_angle),
                    spring_arm_length * math.sin(spring_point_angle))

    knee_mid_angle = math.pi / 2 - arm_neutral_angle

    assert pivot_mount_height >= spring_mount_height

    knee_point1 = (bogie_pivot[0] + (knee_height + 0.2 * thickness) *
                   math.cos(knee_mid_angle - math.radians(knee_angle / 2)),
                   bogie_pivot[1] + (knee_height + 0.2 * thickness) *
                   math.sin(knee_mid_angle - math.radians(knee_angle / 2)))
    knee_point2 = (
        bogie_pivot[0] +
        knee_height * math.cos(knee_mid_angle + math.radians(knee_angle / 2)),
        bogie_pivot[1] +
        knee_height * math.sin(knee_mid_angle + math.radians(knee_angle / 2)))
    _, p1 = util.outer_tangent(Vector(*knee_point1), 0, Vector(0, 0),
                               (pivot_thickness - thickness) / 2)
    p2, _ = util.outer_tangent(Vector(0, 0), (pivot_thickness - thickness) / 2,
                               Vector(*spring_point), 0)
    outline = polygon2d([(p1.x, p1.y), knee_point1, bogie_pivot, knee_point2, spring_point, (p2.x, p2.y)]) \
        .offset(thickness / 2)
    outline += circle(d=pivot_thickness)

    arm = outline.extruded(width + spring_mount_height, symmetrical=False)

    arm += tools.cone(height=pivot_mount_height - spring_mount_height,
                      upper_diameter=pivot_mount_diameter + 2 * thick_wall,
                      lower_diameter=pivot_thickness,
                      base_height=width + spring_mount_height)

    spring_mount_top_diameter = thickness / 2
    spring_cutout_r0 = spring_mount_height + spring_mount_top_diameter / 2
    spring_down_vector = spring_anchor_point - spring_down_point
    rel_spring_down_angle = math.degrees(
        math.atan2(spring_down_vector.y, spring_down_vector.x) -
        arm_down_angle)
    arm -= spring_cutout_generator(90 + rel_spring_down_angle,
                                   spring_cutout_r0,
                                   2 * arm_length,
                                   (vitamins.spring.diameter / 2 + arm_clearance)) \
        .rotated_z(-90) \
        .translated(spring_point[0], spring_point[1], width + vitamins.spring.diameter / 2 + arm_clearance)

    holes = circle(d=pivot_mount_diameter) + \
        circle(d=bogie_pivot_mount_diameter).translated(*bogie_pivot) + \
        circle(d=spring_mount_diameter).translated(*spring_point)
    arm -= holes.extruded(float("inf"))

    # Pivot screw head countersink
    arm -= cylinder(d=pivot_mount_screw_head_diameter,
                    h=2 * pivot_mount_screw_head_countersink)

    if hole_blinding_layer_height:
        arm += cylinder(
            d=pivot_mount_screw_head_diameter,
            h=hole_blinding_layer_height,
            symmetrical=False).translated_z(pivot_mount_screw_head_countersink)

    return arm
Example #13
0
def get_bogie_wheel_position(angle, side):
    s = math.sin(angle)
    c = math.cos(angle)
    side *= bogie_wheel_spacing / 2
    return Vector(c * side + s * bogie_pivot_z, s * side - c * bogie_pivot_z)
Example #14
0
            bogie_wheel_spacing / 2, wheel_width / 2, wheel_diameter / 2),
        inner_road_wheel.rotated_x(90).translated(
            -bogie_wheel_spacing / 2, wheel_width / 2, wheel_diameter / 2),
        outer_road_wheel.rotated_x(-90).translated(
            bogie_wheel_spacing / 2, -wheel_width / 2, wheel_diameter / 2),
        outer_road_wheel.rotated_x(-90).translated(
            -bogie_wheel_spacing / 2, -wheel_width / 2, wheel_diameter / 2)
    ] + [vitamins.small_bearing] * 4 +
    [road_wheel_screw, road_wheel_screw.lock_nut] * 2 + [vitamins.o_ring] * 8)

# Y offset of a right suspension arm base in an assembly.
arm_base_offset = pivot_guide_length + pivot_screw_head_countersink

# Ofset for matching a piece of track with right suspension assembly
track_offset = Vector(
    arm_length * math.cos(arm_neutral_angle), arm_base_offset - arm_width / 2,
    arm_length * math.sin(arm_neutral_angle) - bogie_pivot_z -
    wheel_diameter / 2)

# Pivot mating surface is at coordinates 0, 0, 0 for both left and right arm

# Position of the matching surface for spring anchor point on the right side
# This one is rotated in print orientation!
spring_anchor_point = Vector(
    spring_anchor_point.x, spring_anchor_point.y, arm_base_offset -
    (arm_width + arm_clearance + vitamins.spring.diameter / 2 +
     vitamins.spring.top_mount_thickness / 2))


def suspension_generator(right,
                         arm_angle=arm_neutral_angle,
                         bogie_angle_fraction=None):