Skip to content

Commit c663348

Browse files
committed
Add loader arm V2 and jigs, update arm and panel geometry
Introduces new loader_arm_v2 module and supporting parameters for L-shaped loader arms, replacing the previous arm implementation. Adds 3D printed jig models for bolt hole cutting and welding. Updates lifetrac_v25.scad and lifetrac_v25_params.scad to use new arm geometry, adjust bucket and cross beam logic, and refines side panel profile and cutout calculations to match the new loader arm design.
1 parent 1659633 commit c663348

File tree

7 files changed

+440
-90
lines changed

7 files changed

+440
-90
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
include <../../lifetrac_v25_params.scad>
2+
3+
module angle_iron_drill_jig() {
4+
leg = ANGLE_2X2_1_4[0];
5+
wall = JIG_WALL_THICKNESS;
6+
length = 100;
7+
8+
difference() {
9+
cube([leg + wall, leg + wall, length]);
10+
translate([wall, wall, -1]) cube([leg + 1, leg + 1, length + 2]);
11+
12+
// Drill holes
13+
translate([wall + leg/2, 0, length/2]) rotate([90,0,0]) cylinder(d=5, h=wall*3, center=true, $fn=16);
14+
translate([0, wall + leg/2, length/2]) rotate([0,90,0]) cylinder(d=5, h=wall*3, center=true, $fn=16);
15+
}
16+
}
17+
angle_iron_drill_jig();
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
include <../../lifetrac_v25_params.scad>
2+
3+
module tube_drill_jig() {
4+
// Fits over 2x6 tube
5+
tube_w = TUBE_2X6_1_4[0];
6+
tube_h = TUBE_2X6_1_4[1];
7+
wall = JIG_WALL_THICKNESS;
8+
9+
bolt_spacing_x = 100;
10+
bolt_spacing_y = 80;
11+
12+
difference() {
13+
// Outer shell
14+
cube([tube_h + 2*wall, tube_w + 2*wall, 50], center=true);
15+
16+
// Inner cutout for tube
17+
cube([tube_h + JIG_CLEARANCE, tube_w + JIG_CLEARANCE, 50+2], center=true);
18+
19+
// Drill holes
20+
for (x = [-bolt_spacing_y/2, bolt_spacing_y/2]) // Note: x/y swapped relative to tube orientation in arm file
21+
for (y = [-bolt_spacing_x/2, bolt_spacing_x/2]) // This depends on how jig is oriented
22+
translate([x, 0, 0]) cylinder(d=5, h=tube_w + 2*wall + 2, center=true, $fn=16); // Pilot holes
23+
}
24+
}
25+
26+
tube_drill_jig();
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
include <../../lifetrac_v25_params.scad>
2+
3+
module pivot_welding_jig() {
4+
// Holds two plates apart at TUBE_2X6_1_4[0] (2 inches)
5+
// Aligns DOM pipe
6+
7+
gap = TUBE_2X6_1_4[0];
8+
pipe_od = DOM_PIPE_OD;
9+
10+
difference() {
11+
// Main block
12+
cube([100, gap, 100], center=true);
13+
14+
// Cutout for DOM pipe
15+
rotate([90, 0, 0]) cylinder(d=pipe_od + JIG_CLEARANCE, h=gap+2, center=true, $fn=64);
16+
17+
// Cutouts to save material
18+
cube([80, gap+2, 80], center=true);
19+
}
20+
21+
// Add alignment tabs for plates?
22+
// ...
23+
}
24+
25+
pivot_welding_jig();

LifeTrac-v25/mechanical_design/openscad/lifetrac_v25.scad

Lines changed: 38 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use <modules/structural_steel.scad>
1212
use <modules/fasteners.scad>
1313
use <modules/hydraulics.scad>
1414
use <modules/wheels.scad>
15+
use <modules/loader_arm_v2.scad>
1516

1617
// Import individual part files
1718
use <parts/side_panel.scad>
@@ -163,7 +164,7 @@ animation_phase = animation_time < 0.5 ? (animation_time * 2) : (2 - animation_t
163164

164165
// Default arm position: lowered to ground (animation_phase=0)
165166
// ARM_GROUND_ANGLE is the angle below horizontal needed to reach ground
166-
ARM_LIFT_ANGLE = -ARM_GROUND_ANGLE + (animation_phase * (60 + ARM_GROUND_ANGLE)); // Animate from ground to raised and back
167+
ARM_LIFT_ANGLE = -ARM_GROUND_ANGLE + ARM_V2_OFFSET_ANGLE + (animation_phase * (60 + ARM_GROUND_ANGLE)); // Animate from ground to raised and back
167168

168169
// Cross beam positions along arm length (from pivot)
169170
// First cross beam positioned for bucket cylinder attachment
@@ -175,8 +176,9 @@ CROSS_BEAM_SIZE = TUBE_2X2_1_4[0]; // 2"x2" tube size
175176
CROSS_BEAM_CLEARANCE = 15; // Extra clearance around cross beam in cutout
176177

177178
// Arm rotation range for cutout calculations
178-
ARM_MIN_ANGLE = -ARM_GROUND_ANGLE; // Lowest position (at ground)
179-
ARM_MAX_ANGLE = 60; // Maximum raised position
179+
// ARM_MIN_ANGLE and ARM_MAX_ANGLE are defined in lifetrac_v25_params.scad
180+
// ARM_MIN_ANGLE = -ARM_GROUND_ANGLE; // Lowest position (at ground)
181+
// ARM_MAX_ANGLE = 60; // Maximum raised position
180182

181183
// =============================================================================
182184
// CROSS BEAM CUTOUT GEOMETRY FUNCTIONS
@@ -237,9 +239,9 @@ BUCKET_HEIGHT = 450;
237239

238240
// Bucket tilt angle calculation:
239241
// When arm is at ARM_LIFT_ANGLE, bucket needs to counter-rotate to stay level
240-
// At ground position (ARM_LIFT_ANGLE = -ARM_GROUND_ANGLE), bucket tilts forward to lay flat
241-
// The bucket bottom is horizontal when bucket tilt = ARM_GROUND_ANGLE (compensates for arm angle)
242-
BUCKET_GROUND_TILT = ARM_GROUND_ANGLE; // Tilt needed to make bottom flat when arm at ground
242+
// At ground position (ARM_LIFT_ANGLE = ARM_MIN_ANGLE), bucket tilts forward to lay flat
243+
// The bucket bottom is horizontal when bucket tilt = -ARM_MIN_ANGLE (compensates for arm angle)
244+
BUCKET_GROUND_TILT = -ARM_MIN_ANGLE; // Tilt needed to make bottom flat when arm at ground
243245
BUCKET_MAX_CURL = 60; // Maximum curl angle when fully raised
244246

245247
// Bucket actuates with the arm using the same animation_phase for looping
@@ -1497,7 +1499,7 @@ module stiffener_side_panel_cutters(is_inner, is_left) {
14971499
// Mid Plate Parameters
14981500
mid_y = 800;
14991501
mid_z_start = FRAME_Z_OFFSET + 100;
1500-
mid_z_end = FRAME_Z_OFFSET + 825 - 25.4;
1502+
mid_z_end = FRAME_Z_OFFSET + 350;
15011503
mid_h = mid_z_end - mid_z_start;
15021504
mid_angle_size = [50.8, 6.35];
15031505
mid_leg = mid_angle_size[0];
@@ -1813,7 +1815,7 @@ module base_frame() {
18131815

18141816
// Mid plate (at Y=800 to avoid cylinder bolts at 700)
18151817
// Top height at Y=800 is approx 825mm above frame bottom
1816-
mid_stiffener_plate(800, FRAME_Z_OFFSET + 100, FRAME_Z_OFFSET + 825 - 25.4);
1818+
mid_stiffener_plate(800, FRAME_Z_OFFSET + 100, FRAME_Z_OFFSET + 350);
18171819
}
18181820

18191821
// =============================================================================
@@ -2045,84 +2047,37 @@ module wheel_assemblies() {
20452047
// LOADER ARMS
20462048
// =============================================================================
20472049

2048-
module single_arm(side) {
2049-
mirror_x = (side == "left") ? -1 : 1;
2050-
arm_x = mirror_x * ARM_SPACING/2;
2051-
tube_size = ARM_TUBE_SIZE[0];
2052-
2053-
color("Orange")
2054-
translate([arm_x, 0, 0])
2055-
{
2056-
// Main arm beam - extends from Y=0 (pivot) to Y=ARM_LENGTH (bucket end)
2057-
// Using a hollow square tube created directly with difference()
2058-
translate([0, ARM_LENGTH/2, 0])
2059-
difference() {
2060-
cube([tube_size, ARM_LENGTH, tube_size], center=true);
2061-
cube([tube_size - 2*ARM_TUBE_SIZE[1], ARM_LENGTH + 2, tube_size - 2*ARM_TUBE_SIZE[1]], center=true);
2062-
}
2063-
2064-
// Pivot reinforcement - TYPE B: Two CNC plasma cut rings from 3/4" plate
2065-
// Welded to each side of arm tube at pivot point
2066-
translate([0, 0, 0])
2067-
rotate([0, 90, 0]) {
2068-
// Inner ring
2069-
translate([0, 0, -tube_size/2 + PLATE_3_4_INCH/2])
2070-
pivot_ring_large(tube_size + 30, PIVOT_PIN_DIA + 2);
2071-
// Outer ring
2072-
translate([0, 0, tube_size/2 - PLATE_3_4_INCH/2])
2073-
pivot_ring_large(tube_size + 30, PIVOT_PIN_DIA + 2);
2074-
}
2075-
2076-
// Lift cylinder attachment - TYPE A: U-Channel from 3"x3" tube with pin
2077-
translate([0, LIFT_CYL_ARM_OFFSET, -tube_size/2 - TUBE_3X3_1_4[0]/2])
2078-
rotate([0, 0, 0])
2079-
u_channel_lug_with_pin(TUBE_3X3_1_4, 80, BOLT_DIA_1 + 2);
2080-
2081-
// Note: Bucket cylinder brackets are now on the cross beam, not individual arms
2082-
}
2083-
}
20842050

2085-
module arm_cross_beams() {
2086-
tube_size = ARM_TUBE_SIZE[0];
2087-
cross_tube_size = TUBE_2X2_1_4[0];
2088-
wall_thickness = TUBE_2X2_1_4[1];
2089-
beam_length = ARM_SPACING + tube_size; // Span full width including arm tubes
2090-
2091-
// First cross beam - at bucket cylinder attachment position
2092-
color("Orange")
2093-
translate([0, CROSS_BEAM_1_POS, 0])
2094-
{
2095-
// Cross beam tube
2096-
difference() {
2097-
cube([beam_length, cross_tube_size, cross_tube_size], center=true);
2098-
cube([beam_length + 2, cross_tube_size - 2*wall_thickness, cross_tube_size - 2*wall_thickness], center=true);
2099-
}
2100-
2101-
// Bucket cylinder mounting brackets - TYPE A: U-Channel from 3"x3" tube with pins
2102-
for (side = [-1, 1]) {
2103-
translate([side * BUCKET_CYL_X_SPACING, 0, cross_tube_size/2 + TUBE_3X3_1_4[0]/2])
2104-
u_channel_lug_with_pin(TUBE_3X3_1_4, 80, BOLT_DIA_3_4 + 2);
2105-
}
2106-
}
2107-
2108-
// Second cross beam - near bucket (centered on X=0)
2109-
color("Orange")
2110-
translate([0, CROSS_BEAM_2_POS, 0])
2111-
difference() {
2112-
cube([beam_length, cross_tube_size, cross_tube_size], center=true);
2113-
cube([beam_length + 2, cross_tube_size - 2*wall_thickness, cross_tube_size - 2*wall_thickness], center=true);
2114-
}
2115-
}
21162051

21172052
module loader_arms() {
21182053
if (show_loader_arms) {
21192054
translate([0, ARM_PIVOT_Y, ARM_PIVOT_Z])
2120-
rotate([ARM_LIFT_ANGLE, 0, 0])
2121-
translate([0, 0, 0]) // Local arm coordinate system
2055+
rotate([is_undef(ARM_LIFT_ANGLE) ? 0 : ARM_LIFT_ANGLE, 0, 0])
21222056
{
2123-
single_arm("left");
2124-
single_arm("right");
2125-
arm_cross_beams();
2057+
// Left Arm
2058+
translate([-ARM_SPACING/2, 0, 0])
2059+
rotate([0, 0, 90])
2060+
translate([0, -TUBE_2X6_1_4[0]/2, -TUBE_2X6_1_4[1]/2])
2061+
loader_arm_v2(angle=0, side="left");
2062+
2063+
// Right Arm
2064+
translate([ARM_SPACING/2, 0, 0])
2065+
rotate([0, 0, 90])
2066+
translate([0, -TUBE_2X6_1_4[0]/2, -TUBE_2X6_1_4[1]/2])
2067+
loader_arm_v2(angle=0, side="right");
2068+
2069+
// Cross Beam
2070+
// Connects the elbow assemblies at the new mounting hole position
2071+
// Hole is at main_tube_len - 50 from pivot
2072+
// Z height is 0 relative to arm pivot (center of tube)
2073+
// Y position is ARM_PIVOT_Y + (ARM_MAIN_LEN - 50)
2074+
// But we are inside the rotated arm group, so we use local coordinates
2075+
// The arms are at +/- ARM_SPACING/2
2076+
// The cross beam spans between them
2077+
2078+
translate([0, ARM_MAIN_LEN - 50, 0])
2079+
rotate([0, 90, 0])
2080+
cube([50.8, 152.4, ARM_SPACING], center=true); // 2x6 tube
21262081
}
21272082
}
21282083
}
@@ -2249,8 +2204,8 @@ module bucket() {
22492204
module bucket_attachment() {
22502205
if (show_bucket) {
22512206
translate([0, ARM_PIVOT_Y, ARM_PIVOT_Z])
2252-
rotate([ARM_LIFT_ANGLE, 0, 0])
2253-
translate([0, ARM_LENGTH, 0])
2207+
rotate([is_undef(ARM_LIFT_ANGLE) ? 0 : ARM_LIFT_ANGLE, 0, 0])
2208+
translate([0, ARM_TIP_X, ARM_TIP_Z])
22542209
{
22552210
// Pivot pin connecting arms to bucket
22562211
// This is at the arm tip, aligned with arm centerline
@@ -2275,7 +2230,7 @@ module bucket_attachment() {
22752230
// So we offset the bucket up so that point aligns with the arm tip (Z=0 here)
22762231
// Additional offset to keep bucket bottom above ground
22772232
rotate([BUCKET_TILT_ANGLE, 0, 0])
2278-
translate([0, 0, BOBCAT_QA_HEIGHT]) // Shift bucket up fully so bottom clears ground
2233+
translate([0, 100, BUCKET_HEIGHT - 100]) // Shift bucket up (less 100mm) to reach ground from raised pivot
22792234
bucket();
22802235
}
22812236
}

LifeTrac-v25/mechanical_design/openscad/lifetrac_v25_params.scad

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ WHEEL_X_OFFSET = TRACK_WIDTH/2 + SANDWICH_SPACING/2 + PANEL_THICKNESS + WHEEL_WI
6969

7070
// Design constraints
7171
BUCKET_GROUND_CLEARANCE = 0; // Bucket bottom at ground level when lowered
72-
BUCKET_FRONT_CLEARANCE = 100; // 100mm (~4") clearance between bucket back and front of machine
72+
BUCKET_FRONT_CLEARANCE = 0; // Reduced from 100 to 0 to match shorter arms
7373

7474
// Arm pivot point (at top rear of side panels - tall end)
7575
ARM_PIVOT_Y = 200; // Near rear of machine, between sandwich plates
@@ -84,9 +84,61 @@ ARM_GROUND_ANGLE = asin(ARM_PIVOT_Z / ARM_LENGTH); // Angle below horizontal (d
8484
ARM_TUBE_SIZE = TUBE_3X3_1_4; // 3"x3" arm tubing
8585
ARM_SPACING = TRACK_WIDTH; // Distance between arm centerlines
8686

87+
// =============================================================================
88+
// LOADER ARM V2 PARAMETERS (L-SHAPE)
89+
// =============================================================================
90+
91+
TUBE_2X6_1_4 = [50.8, 152.4, 6.35]; // 2"x6" rectangular tubing
92+
ARM_ANGLE = 120; // Main arm angle in degrees
93+
ARM_PLATE_THICKNESS = PLATE_1_4_INCH;
94+
DOM_PIPE_OD = 50.8; // Approximate OD for pivot holder (2" DOM)
95+
DOM_PIPE_ID = 38.1; // ID matching 1.5" pivot pin
96+
JIG_WALL_THICKNESS = 4; // Standard wall thickness for 3D printed jigs
97+
JIG_CLEARANCE = 0.5; // Clearance for fit
98+
99+
echo("DEBUG: Loading lifetrac_v25_params.scad - Version with Fixes");
100+
101+
// Arm Dimensions for Calculation
102+
ARM_MAIN_LEN = 1100; // Reduced from 1200 to bring bucket closer
103+
ARM_DROP_LEN = 550; // Shortened from 600
104+
ARM_OVERLAP = 200;
105+
ARM_DROP_EXT = 80; // Extension for bucket clearance
106+
ARM_PIVOT_EXT = 40; // Pivot hole offset from end of drop
107+
108+
// Calculate Effective Arm Length and Angle
109+
// Vector from Main Pivot to Bucket Pivot
110+
_bend_angle = 180 - ARM_ANGLE;
111+
_drop_vec_len = ARM_DROP_LEN + ARM_PIVOT_EXT;
112+
_tube_h = TUBE_2X6_1_4[1];
113+
114+
_dx = _drop_vec_len * cos(_bend_angle) + (-_tube_h/2) * sin(_bend_angle);
115+
_dz = -_drop_vec_len * sin(_bend_angle) + (-_tube_h/2) * cos(_bend_angle);
116+
117+
ARM_TIP_X = (ARM_MAIN_LEN + ARM_OVERLAP + 50) + _dx;
118+
ARM_TIP_Z = _tube_h + _dz;
119+
120+
_x_rel = ARM_TIP_X;
121+
_z_rel = ARM_TIP_Z - _tube_h/2;
122+
123+
_arm_eff_len = sqrt(pow(_x_rel, 2) + pow(_z_rel, 2));
124+
arm_alpha_calc = atan2(-_z_rel, _x_rel); // Angle below horizontal (positive value)
125+
126+
// Target Angle Calculation
127+
_target_height = 100; // Raised to 100mm (approx 4") to keep arm tip off ground
128+
_theta_rad = asin((_target_height - ARM_PIVOT_Z) / _arm_eff_len);
129+
theta_deg_calc = _theta_rad;
130+
131+
echo("DEBUG: theta_deg_calc", theta_deg_calc);
132+
echo("DEBUG: arm_alpha_calc", arm_alpha_calc);
133+
134+
ARM_MIN_ANGLE_COMPUTED = (is_undef(theta_deg_calc) || is_undef(arm_alpha_calc)) ? 0 : theta_deg_calc + arm_alpha_calc;
135+
echo("DEBUG: ARM_MIN_ANGLE_COMPUTED", ARM_MIN_ANGLE_COMPUTED);
136+
87137
// Arm angle limits
88-
ARM_MIN_ANGLE = -ARM_GROUND_ANGLE; // Lowest position (at ground)
89-
ARM_MAX_ANGLE = 60; // Maximum raised position
138+
// Calculated to keep bucket pivot ~50mm above ground at lowest position
139+
ARM_V2_OFFSET_ANGLE = ARM_MIN_ANGLE_COMPUTED + ARM_GROUND_ANGLE; // Difference from straight arm
140+
ARM_MIN_ANGLE = ARM_MIN_ANGLE_COMPUTED; // Lowest position (at ground)
141+
ARM_MAX_ANGLE = 60 + ARM_V2_OFFSET_ANGLE; // Maximum raised position
90142

91143
// Cross beam configuration
92144
CROSS_BEAM_SIZE = TUBE_2X2_1_4[0]; // 2"x2" tube size
@@ -285,3 +337,12 @@ assert(PLATFORM_PIVOT_PIN_DIA > PLATFORM_LOCK_PIN_DIA,
285337
_crossmember_top_z = FRAME_Z_OFFSET + MACHINE_HEIGHT * 0.7;
286338
assert(PLATFORM_PIVOT_HEIGHT + PLATFORM_ARM_LENGTH < _crossmember_top_z,
287339
"Stowed position lock hole must be within rear crossmember height");
340+
341+
// =============================================================================
342+
// JIG PARAMETERS & NEW ARM PARAMETERS
343+
// =============================================================================
344+
345+
346+
347+
348+

0 commit comments

Comments
 (0)