mirror of
https://github.com/DJSundog/NopSCADlib.git
synced 2024-11-27 09:10:02 -05:00
Added parameterised CoreXY.
This commit is contained in:
parent
da4f9fbdc3
commit
4c12d5fca4
134
tests/core_xy_belts.scad
Normal file
134
tests/core_xy_belts.scad
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
//
|
||||||
|
// NopSCADlib Copyright Chris Palmer 2020
|
||||||
|
// nop.head@gmail.com
|
||||||
|
// hydraraptor.blogspot.com
|
||||||
|
//
|
||||||
|
// This file is part of NopSCADlib.
|
||||||
|
//
|
||||||
|
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||||
|
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||||
|
// the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
// See the GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||||
|
// If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
include <../core.scad>
|
||||||
|
include <../vitamins/pulleys.scad>
|
||||||
|
include <../vitamins/screws.scad>
|
||||||
|
include <../vitamins/stepper_motors.scad>
|
||||||
|
include <../vitamins/washers.scad>
|
||||||
|
|
||||||
|
include <../utils/core_xy_belts.scad>
|
||||||
|
|
||||||
|
|
||||||
|
module coreXY_belts_test() {
|
||||||
|
coreXY_type = coreXY_GT2_20_16;
|
||||||
|
plain_idler = coreXY_plain_idler(coreXY_type);
|
||||||
|
toothed_idler = coreXY_toothed_idler(coreXY_type);
|
||||||
|
|
||||||
|
coreXYPosBL = [0, 0, 0];
|
||||||
|
coreXYPosTR = [200, 150, 0];
|
||||||
|
separation = [0, coreXY_coincident_separation(coreXY_type).y, pulley_height(plain_idler) + washer_thickness(M3_washer)];
|
||||||
|
pos = [100, 50];
|
||||||
|
|
||||||
|
upper_drive_pulley_offset = [40, 10];
|
||||||
|
lower_drive_pulley_offset = [0, 0];
|
||||||
|
|
||||||
|
coreXY_belts(coreXY_type,
|
||||||
|
carriagePosition = pos,
|
||||||
|
coreXYPosBL = coreXYPosBL,
|
||||||
|
coreXYPosTR = coreXYPosTR,
|
||||||
|
separation = separation,
|
||||||
|
x_gap = 10,
|
||||||
|
upper_drive_pulley_offset = upper_drive_pulley_offset,
|
||||||
|
lower_drive_pulley_offset = lower_drive_pulley_offset,
|
||||||
|
show_pulleys = true);
|
||||||
|
|
||||||
|
|
||||||
|
translate([coreXYPosBL.x + separation.x/2, coreXYPosTR.y + upper_drive_pulley_offset.y, separation.z/2]) {
|
||||||
|
// add the upper drive pulley stepper motor
|
||||||
|
translate([coreXY_drive_pulley_x_alignment(coreXY_type) + upper_drive_pulley_offset.x, 0, -pulley_height(coreXY_drive_pulley(coreXY_type))])
|
||||||
|
NEMA(NEMA17M);
|
||||||
|
|
||||||
|
// add the screws for the upper drive offset idler pulleys if required
|
||||||
|
if (upper_drive_pulley_offset.x > 0) {
|
||||||
|
translate(coreXY_drive_plain_idler_offset(coreXY_type))
|
||||||
|
translate_z(-pulley_offset(plain_idler))
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
translate(coreXY_drive_toothed_idler_offset(coreXY_type))
|
||||||
|
translate_z(-pulley_offset(toothed_idler))
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
} else if (upper_drive_pulley_offset.x < 0) {
|
||||||
|
translate([-pulley_od(plain_idler), coreXY_drive_plain_idler_offset(coreXY_type).y])
|
||||||
|
translate_z(-pulley_offset(plain_idler))
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
translate([2*coreXY_drive_pulley_x_alignment(coreXY_type), coreXY_drive_toothed_idler_offset(coreXY_type).y])
|
||||||
|
translate_z(-pulley_offset(toothed_idler))
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
translate([coreXYPosTR.x - separation.x/2, coreXYPosTR.y + lower_drive_pulley_offset.y, -separation.z/2]) {
|
||||||
|
// add the lower drive pulley stepper motor
|
||||||
|
translate([-coreXY_drive_pulley_x_alignment(coreXY_type) + lower_drive_pulley_offset.x, 0, -pulley_height(coreXY_drive_pulley(coreXY_type))])
|
||||||
|
NEMA(NEMA17M);
|
||||||
|
|
||||||
|
// add the screws for the lower drive offset idler pulleys if required
|
||||||
|
if (lower_drive_pulley_offset.x < 0) {
|
||||||
|
translate([-coreXY_drive_plain_idler_offset(coreXY_type).x, coreXY_drive_plain_idler_offset(coreXY_type).y])
|
||||||
|
translate_z(-pulley_offset(plain_idler))
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
translate(coreXY_drive_toothed_idler_offset(coreXY_type))
|
||||||
|
translate_z(-pulley_offset(toothed_idler))
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
} else if (lower_drive_pulley_offset.x > 0) {
|
||||||
|
translate([pulley_od(plain_idler), coreXY_drive_plain_idler_offset(coreXY_type).y])
|
||||||
|
translate_z(-pulley_offset(plain_idler))
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
translate([-2*coreXY_drive_pulley_x_alignment(coreXY_type), coreXY_drive_toothed_idler_offset(coreXY_type).y])
|
||||||
|
translate_z(-pulley_offset(toothed_idler))
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the screw for the left upper idler pulley
|
||||||
|
translate([coreXYPosBL.x + separation.x/2, coreXYPosBL.y, separation.z])
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
|
||||||
|
// add the screw for the right upper idler pulley
|
||||||
|
translate([coreXYPosTR.x + separation.x/2, coreXYPosBL.y, separation.z])
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
|
||||||
|
if (separation.x != 0) {
|
||||||
|
// add the screw for the left lower idler pulley
|
||||||
|
translate([coreXYPosBL.x - separation.x/2, coreXYPosBL.y, 0])
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
|
||||||
|
// add the screw for the right lower idler pulley
|
||||||
|
translate([coreXYPosTR.x - separation.x/2, coreXYPosBL.y, 0])
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
translate([-separation.x/2, pos.y + coreXYPosBL.y -separation.y/2, -separation.z/2 + pulley_height(plain_idler)/2]) {
|
||||||
|
// add the screw for the left Y carriage toothed idler
|
||||||
|
translate([coreXYPosBL.x, coreXY_toothed_idler_offset(coreXY_type).y, 0])
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
// add the screw for the left Y carriage plain idler
|
||||||
|
translate([coreXYPosBL.x + separation.x + coreXY_plain_idler_offset(coreXY_type).x, separation.y + coreXY_plain_idler_offset(coreXY_type).y, separation.z])
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
// add the screw for the right Y carriage toothed idler
|
||||||
|
translate([coreXYPosTR.x + separation.x, coreXY_toothed_idler_offset(coreXY_type).y, separation.z])
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
// add the screw for the right Y carriage plain idler
|
||||||
|
translate([coreXYPosTR.x - coreXY_plain_idler_offset(coreXY_type).x, separation.y + coreXY_plain_idler_offset(coreXY_type).y, 0])
|
||||||
|
screw(M3_cap_screw, 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($preview)
|
||||||
|
coreXY_belts_test();
|
198
utils/core_xy_belts.scad
Normal file
198
utils/core_xy_belts.scad
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
//
|
||||||
|
// NopSCADlib Copyright Chris Palmer 2020
|
||||||
|
// nop.head@gmail.com
|
||||||
|
// hydraraptor.blogspot.com
|
||||||
|
//
|
||||||
|
// This file is part of NopSCADlib.
|
||||||
|
//
|
||||||
|
// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
||||||
|
// GNU General Public License as published by the Free Software Foundation, either version 3 of
|
||||||
|
// the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
// See the GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with NopSCADlib.
|
||||||
|
// If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
//! Parameterised Core XY implementation. Draws the belts and provides utilities for positioning the pulleys.
|
||||||
|
//!
|
||||||
|
//! The belts are positioned according the bottom left "anchor" pulley and the top right drive pulley.
|
||||||
|
//! Implementation has the following features:
|
||||||
|
//! 1. The drive and idler pulleys may be different sizes.
|
||||||
|
//! 2. The belt separation is parameterised.
|
||||||
|
//! 3. The separation of the plain and toothed pulleys on the Y carriages is parameterised, in both the X and the Y direction.
|
||||||
|
//! 4. The drive pulleys may be offset in the X and Y directions. If this is done, extra idler pulleys are added. This
|
||||||
|
//! allows flexible positioning of the motors.
|
||||||
|
//
|
||||||
|
include <../core.scad>
|
||||||
|
include <../vitamins/belts.scad>
|
||||||
|
include <../vitamins/pulleys.scad>
|
||||||
|
|
||||||
|
|
||||||
|
coreXY_GT2_20_20 = ["coreXY_20_20", GT2x6, GT2x20ob_pulley, GT2x20_toothed_idler, GT2x20_plain_idler, [0, 0, 1], [0, 0, 0.5, 1], [0, 1, 0], [0, 0.5, 0, 1] ];
|
||||||
|
coreXY_GT2_20_16 = ["coreXY_20_16", GT2x6, GT2x20ob_pulley, GT2x16_toothed_idler, GT2x16_plain_idler, [0, 0, 1], [0, 0, 0.5, 1], [0, 1, 0], [0, 0.5, 0, 1] ];
|
||||||
|
coreXY_GT2_16_16 = ["coreXY_16_16", GT2x6, GT2x16_pulley, GT2x16_toothed_idler, GT2x16_plain_idler, [0, 0, 1], [0, 0, 0.5, 1], [0, 1, 0], [0, 0.5, 0, 1] ];
|
||||||
|
|
||||||
|
function coreXY_belt(type) = type[1]; //! Belt type
|
||||||
|
function coreXY_drive_pulley(type) = type[2]; //! Drive pulley type
|
||||||
|
function coreXY_toothed_idler(type) = type[3]; //! Toothed idler type
|
||||||
|
function coreXY_plain_idler(type) = type[4]; //! Plain idler type
|
||||||
|
function coreXY_upper_belt_colour(type) = type[5]; //! Colour of the upper belt
|
||||||
|
function coreXY_upper_tooth_colour(type) = type[6]; //! Colour of the upper belt's teeth
|
||||||
|
function coreXY_lower_belt_colour(type) = type[7]; //! Colour of the lower belt
|
||||||
|
function coreXY_lower_tooth_colour(type) = type[8]; //! Colour of the lower belt's teeth
|
||||||
|
|
||||||
|
// used to offset the position of the drive pulley and the y-carriage plain idler pulley
|
||||||
|
// relative to the anchor pulley so that the belts align properly
|
||||||
|
function coreXY_drive_pulley_x_alignment(type) = //! Belt alignment offset of the drive pulley relative to the anchor pulley
|
||||||
|
(pulley_od(coreXY_drive_pulley(type)) - pulley_od(coreXY_toothed_idler(type))) / 2;
|
||||||
|
function coreXY_coincident_separation(type) = //! Value of x, y separation to make y-carriage pulleys coincident
|
||||||
|
[ -coreXY_plain_idler_offset(type).x, -(pulley_od(coreXY_plain_idler(type)) + pulley_od(coreXY_toothed_idler(type)))/2, 0 ];
|
||||||
|
function coreXY_plain_idler_offset(type) = //! Offset of y-carriage plain idler
|
||||||
|
[ (pulley_od(coreXY_plain_idler(type)) + pulley_od(coreXY_drive_pulley(type))) / 2 + coreXY_drive_pulley_x_alignment(type), pulley_od(coreXY_plain_idler(type))/2, 0 ];
|
||||||
|
function coreXY_toothed_idler_offset(type) = //! offset of y-carriage toothed idler
|
||||||
|
[ 0, -pulley_pr(coreXY_toothed_idler(type)), 0 ];
|
||||||
|
// helper functions for positioning idlers when the stepper motor drive pulley is offset
|
||||||
|
function coreXY_drive_toothed_idler_offset(type) = //! Offset of toothed drive idler pulley
|
||||||
|
[ 0, coreXY_drive_pulley_x_alignment(type), 0 ];
|
||||||
|
function coreXY_drive_plain_idler_offset(type) = //! Offset of plain drive idler pulley
|
||||||
|
[ coreXY_plain_idler_offset(type).x, -(pulley_od(coreXY_plain_idler(type)) + pulley_od(coreXY_drive_pulley(type))) / 2, 0 ];
|
||||||
|
|
||||||
|
|
||||||
|
module coreXY_half(type, size, pos, separation_y = 0, x_gap = 0, plain_idler_offset = 0, drive_pulley_offset = [0, 0], show_pulleys = false, lower_belt = false, hflip = false) { //! Draw one belt of a coreXY setup
|
||||||
|
|
||||||
|
// y-carriage toothed pulley
|
||||||
|
p0_type = coreXY_toothed_idler(type);
|
||||||
|
p0 = [ size.x / 2, -size.y / 2 - pulley_od(p0_type) / 2 + pos.y - separation_y / 2 ];
|
||||||
|
|
||||||
|
// bottom right toothed idler pulley
|
||||||
|
p1_type = p0_type;
|
||||||
|
p1 = [ size.x / 2, -size.y / 2 ];
|
||||||
|
|
||||||
|
// bottom left anchor toothed idler pulley
|
||||||
|
p2_type = p0_type;
|
||||||
|
p2 = [ -size.x / 2, -size.y / 2 ];
|
||||||
|
|
||||||
|
// stepper motor drive pulley
|
||||||
|
p3d_type = coreXY_drive_pulley(type);
|
||||||
|
p3d = [ -size.x / 2 + coreXY_drive_pulley_x_alignment(type) + drive_pulley_offset.x,
|
||||||
|
size.y / 2 + drive_pulley_offset.y
|
||||||
|
];
|
||||||
|
|
||||||
|
// toothed idler for offset stepper motor drive pulley
|
||||||
|
p3t_type = coreXY_toothed_idler(type);
|
||||||
|
p3t = [ -size.x / 2 + (drive_pulley_offset.x > 0 ? 0 : 2*coreXY_drive_pulley_x_alignment(type)),
|
||||||
|
size.y / 2 + coreXY_drive_pulley_x_alignment(type) + drive_pulley_offset.y
|
||||||
|
];
|
||||||
|
|
||||||
|
// y-carriage plain pulley
|
||||||
|
p4_type = coreXY_plain_idler(type);
|
||||||
|
p4 = [ -size.x / 2 + pulley_od(p4_type) / 2 + pulley_od(p3d_type) / 2 + coreXY_drive_pulley_x_alignment(type) + plain_idler_offset,
|
||||||
|
-size.y / 2 + pulley_od(p4_type) / 2 + pos.y + separation_y / 2
|
||||||
|
];
|
||||||
|
|
||||||
|
// plain idler for offset stepper motor drive pulley
|
||||||
|
p3p_type = p4_type;
|
||||||
|
//p3p = [ p4.x, size.y / 2 - pulley_od(p3p_type) / 2 - pulley_od(p3d_type) / 2 + drive_pulley_offset.y ];
|
||||||
|
p3p = [ drive_pulley_offset.x > 0 ? p4.x : -p0.x - pulley_od(p0_type),
|
||||||
|
size.y / 2 - pulley_od(p3p_type) / 2 - pulley_od(p3d_type) / 2 + drive_pulley_offset.y
|
||||||
|
];
|
||||||
|
|
||||||
|
// dummy pulleys for y separation
|
||||||
|
p5_type = p4_type;
|
||||||
|
p5 = [ pos.x - size.x / 2, -size.y / 2 + pos.y + separation_y / 2 ];
|
||||||
|
p6_type = p0_type;
|
||||||
|
p6 = [ pos.x - size.x / 2, -size.y / 2 + pos.y - separation_y / 2 ];
|
||||||
|
|
||||||
|
module show_pulleys(show_pulleys) {// Allows the pulley colour to be set for debugging
|
||||||
|
not_on_bom()
|
||||||
|
if (is_list(show_pulleys))
|
||||||
|
color(show_pulleys)
|
||||||
|
children();
|
||||||
|
else if (show_pulleys)
|
||||||
|
children();
|
||||||
|
}
|
||||||
|
|
||||||
|
show_pulleys(show_pulleys) {
|
||||||
|
translate(p0)
|
||||||
|
pulley_assembly(p0_type); // y-carriage toothed pulley
|
||||||
|
translate(p1)
|
||||||
|
pulley_assembly(p1_type); // bottom right toothed idler pulley
|
||||||
|
translate(p2)
|
||||||
|
pulley_assembly(p2_type); // bottom left anchor toothed idler pulley
|
||||||
|
translate(p3d)
|
||||||
|
hflip(hflip)
|
||||||
|
pulley_assembly(p3d_type); // top left stepper motor drive pulley
|
||||||
|
if (drive_pulley_offset.x) { // idler pulleys for offset stepper motor drive pulley
|
||||||
|
translate(p3t)
|
||||||
|
pulley_assembly(p3t_type); // toothed idler
|
||||||
|
translate(p3p)
|
||||||
|
pulley_assembly(p3p_type); // plain idler
|
||||||
|
}
|
||||||
|
translate(p4)
|
||||||
|
pulley_assembly(p4_type); // y-carriage plain pulley
|
||||||
|
}
|
||||||
|
|
||||||
|
path0a = [
|
||||||
|
[ p0.x, p0.y, pulley_od(p0_type) / 2 ],
|
||||||
|
[ p1.x, p1.y, pulley_od(p1_type) / 2 ],
|
||||||
|
[ p2.x, p2.y, pulley_od(p2_type) / 2 ]
|
||||||
|
];
|
||||||
|
path0b = [
|
||||||
|
[ p3d.x, p3d.y, pulley_od(p3d_type) / 2 ],
|
||||||
|
[ p4.x, p4.y, -pulley_od(p4_type) / 2 ]
|
||||||
|
];
|
||||||
|
path0c = [
|
||||||
|
[ p3t.x, p3t.y, pulley_od(p3t_type) / 2 ],
|
||||||
|
[ p3d.x, p3d.y, pulley_od(p3d_type) / 2 ],
|
||||||
|
[ p3p.x, p3p.y, -pulley_od(p3p_type) / 2 ],
|
||||||
|
[ p4.x, p4.y, -pulley_od(p4_type) / 2 ]
|
||||||
|
];
|
||||||
|
path0d = [
|
||||||
|
[ p3p.x, p3p.y, -pulley_od(p3p_type) / 2 ],
|
||||||
|
[ p3d.x, p3d.y, pulley_od(p3d_type) / 2 ],
|
||||||
|
[ p3t.x, p3t.y, pulley_od(p3t_type) / 2 ],
|
||||||
|
[ p4.x, p4.y, -pulley_od(p4_type) / 2 ]
|
||||||
|
];
|
||||||
|
path1 = [ // use eps for corner radius to get sharp corners so this part of the belt is deleted by the gap
|
||||||
|
[ p5.x, p5.y, eps ],
|
||||||
|
[ p6.x, p6.y, eps ]
|
||||||
|
];
|
||||||
|
|
||||||
|
belt = coreXY_belt(type);
|
||||||
|
|
||||||
|
path0 = drive_pulley_offset.x == 0 ? concat(path0a, path0b) : drive_pulley_offset.x > 0 ? concat(path0a, path0c) : concat(path0a, path0d);
|
||||||
|
path = separation_y == 0 ? path0 : concat(path0, path1);
|
||||||
|
|
||||||
|
belt(type = belt,
|
||||||
|
points = path,
|
||||||
|
gap = [ x_gap + eps, abs(separation_y) + 2 ],
|
||||||
|
gap_pos = [ pos.x - size.x / 2, pos.y - size.y / 2 + belt_pitch_height(belt) - belt_thickness(belt) / 2 ],
|
||||||
|
belt_colour = lower_belt ? coreXY_lower_belt_colour(type) : coreXY_upper_belt_colour(type),
|
||||||
|
tooth_colour = lower_belt ? coreXY_lower_tooth_colour(type) : coreXY_upper_tooth_colour(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
module coreXY(type, size, pos, separation, x_gap, plain_idler_offset = 0, upper_drive_pulley_offset, lower_drive_pulley_offset, show_pulleys = false) { //! Wrapper module to draw both belts of a coreXY setup
|
||||||
|
translate([size.x / 2 - separation.x / 2, size.y / 2, -separation.z / 2]) {
|
||||||
|
// lower belt
|
||||||
|
hflip()
|
||||||
|
explode(25)
|
||||||
|
coreXY_half(type, size, [size.x - pos.x - separation.x, pos.y], separation.y, x_gap, plain_idler_offset, [-lower_drive_pulley_offset.x, lower_drive_pulley_offset.y], show_pulleys, lower_belt = true, hflip = true);
|
||||||
|
// upper belt
|
||||||
|
translate([separation.x, 0, separation.z])
|
||||||
|
explode(25)
|
||||||
|
coreXY_half(type, size, [pos.x, pos.y], separation.y, x_gap, plain_idler_offset, upper_drive_pulley_offset, show_pulleys, lower_belt = false, hflip=false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module coreXY_belts(type, carriagePosition, coreXYPosBL, coreXYPosTR, separation, x_gap = 20, upper_drive_pulley_offset = [0, 0], lower_drive_pulley_offset = [0, 0], show_pulleys = false) { //! Draw the coreXY belts
|
||||||
|
assert(coreXYPosBL.z == coreXYPosTR.z);
|
||||||
|
|
||||||
|
coreXYSize = coreXYPosTR - coreXYPosBL;
|
||||||
|
translate(coreXYPosBL)
|
||||||
|
coreXY(type, coreXYSize, [carriagePosition.x - coreXYPosBL.x + separation.x / 2, carriagePosition.y - coreXYPosBL.y], separation = separation, x_gap = x_gap, plain_idler_offset = 0, upper_drive_pulley_offset = upper_drive_pulley_offset, lower_drive_pulley_offset = lower_drive_pulley_offset, show_pulleys = show_pulleys);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user