Main Restorations Software Audio/Jukebox/MP3 Everything Else Buy/Sell/Trade
Project Announcements Monitor/Video GroovyMAME Merit/JVL Touchscreen Meet Up Retail Vendors
Driving & Racing Woodworking Software Support Forums Consoles Project Arcade Reviews
Automated Projects Artwork Frontend Support Forums Pinball Forum Discussion Old Boards
Raspberry Pi & Dev Board controls.dat Linux Miscellaneous Arcade Wiki Discussion Old Archives
Lightguns Arcade1Up Try the site in https mode Site News

Unread posts | New Replies | Recent posts | Rules | Chatroom | Wiki | File Repository | RSS | Submit news

  

Author Topic: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade  (Read 11394 times)

0 Members and 1 Guest are viewing this topic.

PL1

  • Global Moderator
  • Trade Count: (+1)
  • Full Member
  • *****
  • Online Online
  • Posts: 9393
  • Last login:Today at 07:06:08 am
  • Designated spam hunter
Like the title says, this is the thread for developing and testing a printable LS-30 handle for the J-Stik/ServoStik Ikari 12-way Rotary Upgrade announced here.

Ultimarc product page:
http://www.ultimarc.com/controls.html

Installation directions:
http://www.ultimarc.com/12wayrotary.pdf

Anyone who wants to join in, grab a copy of OpenSCAD and bookmark the OpenSCAD cheatsheet to help you with the commands and syntax.   ;D

---------------------

The plan is to start with the code from the 3d printed LS-30 replacement handle for the Happ Rotary Joystick and remix it to include these features:

  - Removable top like the original handle.

  - Two free-floating eject pins instead of the long legs on the original top.
(less likely to break and easier to print)


  - M6 locknut and maybe a star washer or two to secure the handle to the shaft.


  - No shaft mods, just print and assemble.

Any more features you'd like to see added or changed?

--------------------

Needed measurements to design the part:

Shaft diagram.


Mounting plate to shaft shoulder distance = 46mm.


Next step:  A diagram to work out the vertical positioning of the handle on the shaft.


Scott
EDIT: Uploaded a copy of the shaft diagram since it is no longer at the old URL.
« Last Edit: October 01, 2021, 05:28:29 pm by PL1 »

05SRT4

  • Trade Count: (+5)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 1092
  • Last login:Yesterday at 08:04:24 pm
  • Check out my Pow Pow
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #1 on: September 12, 2018, 11:40:11 am »
Just ordered the rotary kit.

PL1

  • Global Moderator
  • Trade Count: (+1)
  • Full Member
  • *****
  • Online Online
  • Posts: 9393
  • Last login:Today at 07:06:08 am
  • Designated spam hunter
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #2 on: September 12, 2018, 04:43:29 pm »
Looking forward to your advice and observations, Deven.   ;D

Here's the promised vertical positioning diagram. (Not drawn to scale.)



First thing to do is solve for Shaft Height with a typical 3/4" wood panel (19.05mm) and a typical metal panel (1.6 mm) since most panels will fall within that range.

3/4" wood panel:
  PanelThickness + 15.6mm (handle to panel distance) +ShaftHeight = Shoulder Height
  19.05mm + 15.6mm + ShaftHeight = 46mm
  ShaftHeight = 11.35mm

Metal panel:
  1.6mm + 15.6mm + ShaftHeight = 46mm
  ShaftHeight = 28.8mm

The original handle BodyHeight is 35.6mm, so ShaftHeight + ThreadedHeight + TopThickness (the removable cover) have to fit into that vertical space.

Wood panel:
  ShaftHeight + ThreadedHeight + TopThickness <= BodyHeight
  11.35mm + 9.4mm + TopThickness <= 35.6mm
  TopThickness <= 14.85mm -- Lots of wiggle room there.   ;D

Metal panel:
  28.8mm + 9.4mm + TopThickness <= 35.6mm
  TopThickness <= -2.6mm -- Threads are higher than the handle body, needs some 5mm spacers (or larger) between the stick and panel.

Metal panel + 5mm spacers:
  23.8mm + 9.4mm + TopThickness <= 35.6mm
  TopThickness <= 2.4mm -- Just enough wiggle room for a 2mm top.

------------------

Looks like the handle will work with 6.6mm (metal panel + 5mm spacers) - 19.05mm (3/4" wood) panels and leaves room for a 2mm recess for the top cover.

Next step: Define variable names and trim/organize the code.


Scott
EDIT: Fixed several errors in the metal panel calculations.   :embarassed:
« Last Edit: September 18, 2018, 06:06:08 am by PL1 »

esoteric_rt

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 56
  • Last login:March 19, 2024, 06:11:52 pm
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #3 on: September 12, 2018, 09:38:56 pm »
Great work, id be in for 2 x tops if anyone makes them in nice quality :-)

PL1

  • Global Moderator
  • Trade Count: (+1)
  • Full Member
  • *****
  • Online Online
  • Posts: 9393
  • Last login:Today at 07:06:08 am
  • Designated spam hunter
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #4 on: September 13, 2018, 05:18:38 am »
Test print updated with new variables and comments.   ;D

LS30_Test_Print_Ultimarc.scad
Code: [Select]
// LS-30 handle for Ultimarc Ikari 12-way Rotary Upgrade
// - Test print

// This test print allows you to verify the correct variable values for your specific hardware and your slicer software before you render/export/print the whole handle.

// Hardware tested:
// - Joystick M6 threaded diameter (clears without engaging threads)
// - Joysick shaft diameter (snug fit)

// This part is oriented upside-down compared to the handle so print supports are not needed.

/////////////////////////////
//      Define variables
/////////////////////////////

ShaftDiameter = 9.35;  // Default = 9.35
ShaftHeight = 9;        // Default = 9
ThreadedDiameter = 6.2; // Default = 6.2
// The diameter values may need to be *very slightly* larger to account for the 180-sided polygon used to render circles -- see "undersized holes" at https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Primitive_Solids#cylinder
$fn=180; // Number of fragments (polygon sides) used to render a circle

/////////////////////////////
//      Make the part
/////////////////////////////

// Make the shaft test layer
difference() {
    cylinder(ShaftHeight, d=ShaftDiameter+6, center=true);   // Shaft outer cylinder
    cylinder(ShaftHeight+2, d=ShaftDiameter, center=true);
    // Remove Shaft Collar hole
    }
//
// Make the thread test layer (red)
difference() {
    color("red") translate([0,0,-1 - ShaftHeight/2]) cylinder(2, d=ShaftDiameter + 6, center=true);
    // Outer cylinder
    translate([0,0,-1 - ShaftHeight/2]) cylinder(ShaftHeight, d=ThreadedDiameter, center=true);
    // Remove threaded hole
}


Scott

PL1

  • Global Moderator
  • Trade Count: (+1)
  • Full Member
  • *****
  • Online Online
  • Posts: 9393
  • Last login:Today at 07:06:08 am
  • Designated spam hunter
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #5 on: September 13, 2018, 07:25:00 am »
First pass on the handle updated with new variables and comments.   ;D

LS30_Handle_Ultimarc.scad
Code: [Select]
// LS-30 handle for Ultimarc Ikari 12-way Rotary Upgrade
// -- Handle

// Required hardware:
// - 6mm locknut
// - 6mm star washer

/////////////////////////////
//  Adjustable variables
/////////////////////////////

// Body
    BodyHeight = 35.6; // Default = 35.6
    // Height of the body, not including the dome

    TopDiameter = 22; // Default = 22
    // Hole for remvable top. 2mm deep.

// Sides
    SideRoundSphere = 0.7; // Default = 0.7
    // Radius of the side roundover sphere

    LowerBodyDiameter = 31.51; // Default = 31.51
    // Farthest distance from lower point-to-point edge

    UpperBodyDiameter = 29.41; // Default = 29.41
    // Farthest distance from upper point-to-point edge

// Bottom octagon
    LowerRoundSphere = 1.59; // Default = 1.59
    // Radius of the lower roundover sphere

// Top octagon
    UpperRoundSphere = 3.18; // Default = 3.18
    // Radius of the upper roundover sphere

// Spaces to remove from body
    ShaftHeight = 11.35; // Default = 11.35 (3/4" wood panel) or 23.5 (1.6mm metal panel with 2mm spacers)
    // Height of the unthreaded shaft cavity

    ShaftDiameter = 9.35; // Default = 9.35
    // Diameter of the joystick unthreaded shaft cavity

    ThreadedHeight = 6; // Default = 6
    // Height of the thread hole

    ThreadedDiameter = 6.2; // Default = 6.2
    // Outer diameter of the thread hole
   
    LocknutHeight = (BodyHeight - ShaftHeight - ThreadedHeight);

    LocknutDiameter = 12; // Default = 12
    // Diameter of the locknut cavity

// Number of fragments (polygon sides) used to render a full circle.
    $fn = 180; // Default = 180  Typical range = 6 - 360
    // 6 will render a circular hole as a hexagon, 8 will render a circular hole as an octagon.
    // Lower the number for faster rendering, raise the number for smoother rendering.


/////////////////////////////
//  Non-adjustable variables
/////////////////////////////

// Bottom octagon
    LowerSmallArccosine = SideRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from center of lower small sphere to point of lower octagon [radius*acos(22.5)]

    LowerLargeArccosine = LowerRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from point of lower octagon to center of lower large sphere [radius*acos(22.5)]

    LowerLargeSphereCenter = LowerBodyDiameter/2 - SideRoundSphere + LowerSmallArccosine - LowerLargeArccosine;
    // Rounded octagon point - side (small) sphere radius + distance from center of small sphere to point of octagon - distance from point of octagon to center of large sphere

// Top octagon
    UpperSmallArccosine = SideRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from center of upper small sphere to point of upper octagon [radius*acos(22.5)]

    UpperLargeArccosine = UpperRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from point of upper octagon to center of upper large sphere [radius*acos(22.5)]

    UpperLargeSphereCenter = UpperBodyDiameter/2 - SideRoundSphere + UpperSmallArccosine - UpperLargeArccosine;
    // Rounded octagon point - side (small) sphere radius + distance from center of small sphere to point of octagon - distance from point of octagon to center of large sphere

/////////////////////////////
//  Make the part
/////////////////////////////

// Make the main body
difference(){ // Main body minus holes
    hull() {  // Main body hull
    // Lower roundover large spheres
    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    // Lower side small spheres
    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    // Upper side small spheres
    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere, center = true);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    // Upper roundover large spheres
    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);     

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);
   
    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);
    } // End main body hull

// Holes
color("gray") translate ([0, 0, ShaftHeight/2]) rotate ([0, 0, 0]) cylinder (ShaftHeight+2, d = ShaftDiameter, center=true); // Make hole for Shaft

color("blue") translate ([0, 0, ShaftHeight+ThreadedHeight/2]) cylinder (2 + ThreadedHeight, d = ThreadedDiameter, center=true); // Make hole for threaded

color("white") translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2]) cylinder (LocknutHeight + 1, d = LocknutDiameter, center=true);
    // Make hole for locknut

color("red") translate ([0, 0, BodyHeight]) cylinder (4, d = TopDiameter, center=true);
    // Make hole for removable top

color("green") translate ([-9, 0, 0]) cylinder (6, d = 2, center=true);
    // Eject pin access hole 1

color("green") translate ([9, 0, 0]) cylinder (6, d = 2, center=true);
    // Eject pin access hole 2

color("purple") translate ([-9, 0, BodyHeight/2 + 2]) cylinder (BodyHeight, d = 4, center=true);
    // Eject pin hole 1

color("purple") translate ([9, 0, BodyHeight/2 + 2]) cylinder (BodyHeight, d = 4, center=true);
    // Eject pin hole 2
} //End difference main body hull minus holes
//

Eject pin (print 2)

LS30_Eject_Pin_Ultimarc.scad
Code: [Select]
// LS-30 handle for Ultimarc Ikari 12-way Rotary Upgrade
// -- Eject pin (handle requires 2)

// Number of fragments (polygon sides) used to render a full circle.
    $fn = 180; // Default = 180  Typical range = 6 - 360

/////////////////////////////
//  Make the part
/////////////////////////////

// Make the main body
translate ([0, 0, 15]) cylinder (22, d = 3.8, center=true);  // Eject pin body
translate ([0, 0, 2]) cylinder (4, d1 = 3.2, d2 = 3.8, center=true);  // Eject pin bottom
translate ([0, 0, 28]) cylinder (4, d1 = 3.8, d2 =3.2, center=true);  // Eject pin body


Scott
« Last Edit: September 13, 2018, 07:45:01 am by PL1 »

PL1

  • Global Moderator
  • Trade Count: (+1)
  • Full Member
  • *****
  • Online Online
  • Posts: 9393
  • Last login:Today at 07:06:08 am
  • Designated spam hunter
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #6 on: September 19, 2018, 06:36:20 am »
Almost done.   ;D



Items remaining:
- Print a handle and two pins to confirm two tiny changes.

- Get a 6mm locknut and star washer to confirm, but it looks like there is enough clearance even on a 1.6mm metal panel + 5mm spacers. (panel + spacers = 6.6mm total thickness)

- Review documentation for errors and typos.

I'd greatly appreciate if someone (Deven? :angel:) with a 3d printer and the Ultimarc Upgrade Kit or other Ultimarc 9mm shaft stick can do a test print to check if ShaftDiameter = 9.35 is good default value for a 9mm shaft stick.
-- ShaftDiameter is set on line 21 of LS30_Test_Print_Ultimarc.scad and line 45 of LS30_Handle_Ultimarc.scad.
-- ShaftDiameter = 10.35 works for the 10mm shaft on a Zippyy.

LS30_Test_Print_Ultimarc.scad
Code: [Select]
// LS-30 handle for Ultimarc Ikari 12-way Rotary Upgrade
// - Test print

// Other prints needed:
// -- Handle
// -- Handle top
// -- Eject pin (2 pins per handle)

// This test print allows you to verify the correct variable values for your specific hardware and your slicer software before you render/export/print the whole handle.

// Hardware tested:
// - Joystick M6 threaded diameter (clears without engaging threads)
// - Joysick shaft diameter (snug fit)

// This part is oriented upside-down compared to the handle so print supports are not needed.

/////////////////////////////
//      Define variables
/////////////////////////////

ShaftDiameter = 9.35;  // Default = 9.35
ShaftHeight = 9;        // Default = 9
ThreadedDiameter = 6.2; // Default = 6.2
// The diameter values may need to be *very slightly* larger to account for the 180-sided polygon used to render circles -- see "undersized holes" at [url]https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Primitive_Solids#cylinder[/url]
$fn=180; // Number of fragments (polygon sides) used to render a circle

/////////////////////////////
//      Make the part
/////////////////////////////

// Make the shaft test layer
difference() {
    cylinder(ShaftHeight, d=ShaftDiameter+6, center=true);   // Shaft outer cylinder
    cylinder(ShaftHeight+2, d=ShaftDiameter, center=true);
    // Remove Shaft Collar hole
    }
//
// Make the thread test layer (red)
difference() {
    color("red") translate([0,0,-1 - ShaftHeight/2]) cylinder(2, d=ShaftDiameter + 6, center=true);
    // Outer cylinder
    translate([0,0,-1 - ShaftHeight/2]) cylinder(ShaftHeight, d=ThreadedDiameter, center=true);
    // Remove threaded hole
}

LS30_Handle_Ultimarc.scad
Code: [Select]
// LS-30 handle for Ultimarc Ikari 12-way Rotary Upgrade
// -- Handle

// Other prints needed:
// -- Test print
// -- Handle top
// -- Eject pin (2 pins per handle)

// Required hardware:
// - 6mm locknut
// - 6mm star washer

/////////////////////////////
//  Adjustable variables
/////////////////////////////

// Body
    BodyHeight = 35.6; // Default = 35.6
    // Height of the body, not including the dome

// Sides
    SideRoundSphere = 0.7; // Default = 0.7
    // Radius of the side roundover sphere

    LowerBodyDiameter = 31.51; // Default = 31.51
    // Farthest distance from lower point-to-point edge

    UpperBodyDiameter = 29.41; // Default = 29.41
    // Farthest distance from upper point-to-point edge

// Bottom octagon
    LowerRoundSphere = 1.59; // Default = 1.59
    // Radius of the lower roundover sphere

// Top octagon
    UpperRoundSphere = 3.18; // Default = 3.18
    // Radius of the upper roundover sphere

// Spaces to remove from body
    ShaftHeight = 23.8; // Default = 30.4mm - panel thickness. (This formula positions the bottom of the handle 15.6mm above the top of the panel, same as Ikari Warriors.)
    // 11.35 for a 3/4" wood panel (19.05mm)
    // 23.8 for a 1.6mm metal panel with 5mm spacers (6.6mm)
    // Height of the unthreaded shaft cavity   

    ShaftDiameter = 9.35; // Default = 9.35 for a 9mm shaft
    // Diameter of the joystick unthreaded shaft cavity.  This value needs to be *very slightly* larger than the actual joystick shaft diameter to allow for the 180-sided polygon used to render circles -- see "undersized holes" at [url]https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Primitive_Solids#cylinder[/url]

    ThreadedHeight = 6; // Default = 6
    // Height of the thread hole

    ThreadedDiameter = 6.2; // Default = 6.2
    // Outer diameter of the thread hole

    LocknutDiameter = 12; // Default = 12
    // Diameter of the locknut cavity. (Height is automatically calculated below.)

    PinDistance = 9; // Default =9
    // Horizontal distance from handle center to eject pin center
   
    PinDiameter = 4; // Default = 4
    // Diameter of the eject pin body

    TopDiameter = 22.6; // Default = 22.6
    // Hole for removable top.
   
    TopHeight = 2; // Default = 2
    // Hole for removable top.
   
// Number of fragments (polygon sides) used to render a full circle.
    $fn = 180; // Default = 180  Typical range = 6 - 360
    // 6 will render a circular hole as a hexagon, 8 will render a circular hole as an octagon.
    // Lower the number for faster rendering, raise the number for smoother rendering.


/////////////////////////////
//  Non-adjustable variables
/////////////////////////////

// Bottom octagon
    LowerSmallArccosine = SideRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from center of lower small sphere to point of lower octagon [radius*acos(22.5)]

    LowerLargeArccosine = LowerRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from point of lower octagon to center of lower large sphere [radius*acos(22.5)]

    LowerLargeSphereCenter = LowerBodyDiameter/2 - SideRoundSphere + LowerSmallArccosine - LowerLargeArccosine;
    // Rounded octagon point - side (small) sphere radius + distance from center of small sphere to point of octagon - distance from point of octagon to center of large sphere

// Top octagon
    UpperSmallArccosine = SideRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from center of upper small sphere to point of upper octagon [radius*acos(22.5)]

    UpperLargeArccosine = UpperRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from point of upper octagon to center of upper large sphere [radius*acos(22.5)]

    UpperLargeSphereCenter = UpperBodyDiameter/2 - SideRoundSphere + UpperSmallArccosine - UpperLargeArccosine;
    // Rounded octagon point - side (small) sphere radius + distance from center of small sphere to point of octagon - distance from point of octagon to center of large sphere

// Locknut cavity
    LocknutHeight = (BodyHeight - ShaftHeight - ThreadedHeight);
    // Height of the locknut cavity

/////////////////////////////
//  Make the part
/////////////////////////////

// Make the main body
difference(){ // Main body minus holes
    hull() {  // Main body hull
    // Lower roundover large spheres
    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    // Lower side small spheres
    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    // Upper side small spheres
    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere, center = true);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    // Upper roundover large spheres
    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);     

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);
   
    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);
    } // End main body hull

// Holes
color("limegreen") translate ([0, 0, ShaftHeight/2]) cylinder (ShaftHeight, d = ShaftDiameter, center=true); // Make hole for Shaft

color("blue") translate ([0, 0, ShaftHeight+ThreadedHeight/2]) cylinder (ThreadedHeight + .001, d = ThreadedDiameter, center=true); // Make hole for threaded

color("white") translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2]) cylinder (LocknutHeight + .001, d = LocknutDiameter, center=true);
    // Make hole for locknut

color("red") translate ([0, 0, BodyHeight - TopHeight/2]) cylinder (TopHeight, d = TopDiameter, center=true);
    // Make hole for removable top

color("aqua") translate ([-PinDistance, 0, 1]) cylinder (2.01, d1 = 3.5, d2 = 2, center=true);
    // Eject pin access hole 1

color("aqua") translate ([PinDistance, 0, 1]) cylinder (2.01, d1 = 3.5, d2 = 2, center=true);
    // Eject pin access hole 2

color("purple") translate ([-PinDistance, 0, BodyHeight/2 + 2]) cylinder (BodyHeight, d = PinDiameter, center=true);
    // Eject pin hole 1

color("purple") translate ([PinDistance, 0, BodyHeight/2 + 2]) cylinder (BodyHeight, d = PinDiameter, center=true);
    // Eject pin hole 2
} //End difference main body hull minus holes
//

LS30_Handle_Top_Ultimarc.scad
Code: [Select]
// LS-30 handle for Ultimarc Ikari 12-way Rotary Upgrade
// -- Handle top

// Other prints needed:
// -- Test print
// -- Handle
// -- Eject pin (2 pins per handle)

// Logo exported from Inkscape to .dxf file using [url]https://github.com/brad/Inkscape-OpenSCAD-DXF-Export[/url]

/////////////////////////////
//  Adjustable variables
/////////////////////////////

// Logo
    LogoDepth = 1.0; // Default = 1.0
    // Logo height above the main body

// Dome
    DomeHeight = 0.8; // Default = 0.8
    // Dome height above the main body

    DomeDiameter = 22; // Default = 22
    // This variable is not used to generate the part, but is used to calculate DomeSphereRadius.

    DomeSphereRadius = 76.02; // Default = 76.02
    // Sphere radius that will generate the desired dome.
    // Enter the "Width of Arc" (DomeDiameter) and "Height of Arc" (DomeHeight) into the calculator at http://handymath.com/cgi-bin/arc18mm2.cgi?submit=Entry The resulting "Radius of Arc" = DomeSphereRadius.

// Body
    TopHeight = 2; // Default = 2
    // Height of the body, not including the dome

    TopDiameter = 22.6; // Default = 22.6
    // Diameter of the body that fits inside the handle

    TopWiggleRoom = 0.65; // Default = 0.65
    // Amount to decrease the body diameter for easier insertion/removal of top.  It also allows for the 180-sided polygon used to render circles -- see "undersized holes" at [url]https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Primitive_Solids#cylinder[/url]

    TopTaper = 0.2; // Default = 0.2
    // Amount to reduce the bottom diameter of the body

// Number of fragments (polygon sides) used to render a full circle.
    $fn = 180; // Default = 180  Typical range = 6 - 360
    // 6 will render a circular hole as a hexagon, 8 will render a circular hole as an octagon.
    // Lower the number for faster rendering, raise the number for smoother rendering.


/////////////////////////////
//  Make the part
/////////////////////////////

// Make the SNK Logo (Optional)
// Comment out the next three lines to skip the logo
translate([-6, -3, 0])
linear_extrude(height = LogoDepth, convexity = 10)
import(file = "SNK_Logo.dxf", layer="Logo");
// The "SNK_Logo.dxf" file needs to be in the same directory as this SCAD file.
//

// Make the dome
difference(){ // Sphere minus cube
    translate([0,0,DomeHeight-DomeSphereRadius]) sphere(r=DomeSphereRadius, center=true); // Sphere
    translate([0,0,- DomeSphereRadius]) cube([DomeSphereRadius*2,DomeSphereRadius*2,DomeSphereRadius*2], center=true);
    // Cube to cut off bottom of sphere
}
//

// Make the body
translate ([0, 0, -TopHeight/2]) cylinder (TopHeight, d1 = TopDiameter - TopTaper - TopWiggleRoom, d2 = TopDiameter - TopWiggleRoom, center=true);
//

LS30_Eject_Pin_Ultimarc.scad
Code: [Select]
// LS-30 handle for Ultimarc Ikari 12-way Rotary Upgrade
// -- Eject pin (2 pins per handle)

// Other prints needed:
// -- Test print
// -- Handle
// -- Handle top

/////////////////////////////
//  Adjustable variables
/////////////////////////////

PinHeight = 30; // Default = 30
// Height of the whole pin

TaperHeight = 2; // Default = 2
// Height of the taper on each end

PinDiameter = 4; // Default = 4
// Diameter of the eject pin body

TaperDiameter = 3.2; // Default = 3.2
// Diameter of the pin tips

PinWiggleRoom = 0.5; // Default = 0.5
// Amount to decrease pin diameter and tips for easier insertion/removal.  It also allows for the 180-sided polygon used to render circles -- see "undersized holes" at [url]https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Primitive_Solids#cylinder[/url]

// Number of fragments (polygon sides) used to render a full circle.
    $fn = 180; // Default = 180  Typical range = 6 - 360

/////////////////////////////
//  Make the part
/////////////////////////////

// Make the first pin
translate ([0, 0, PinHeight/2]) cylinder (PinHeight - TaperHeight*2, d = PinDiameter - PinWiggleRoom, center=true);
// Eject pin body 1

translate ([0, 0, TaperHeight/2]) cylinder (TaperHeight, d1 = TaperDiameter - PinWiggleRoom, d2 = PinDiameter - PinWiggleRoom, center=true);
// Eject pin bottom 1

translate ([0, 0, PinHeight - TaperHeight/2]) cylinder (TaperHeight, d1 = PinDiameter - PinWiggleRoom, d2 = TaperDiameter - PinWiggleRoom, center=true);
// Eject pin top 1

// Make the second pin
translate ([0, PinDiameter * 2, PinHeight/2]) cylinder (PinHeight - TaperHeight*2, d = PinDiameter - PinWiggleRoom, center=true);
// Eject pin body 2

translate ([0, PinDiameter * 2, TaperHeight/2]) cylinder (TaperHeight, d1 = TaperDiameter - PinWiggleRoom, d2 = PinDiameter - PinWiggleRoom, center=true);
// Eject pin bottom 2

translate ([0, PinDiameter * 2, PinHeight - TaperHeight/2]) cylinder (TaperHeight, d1 = PinDiameter - PinWiggleRoom, d2 = TaperDiameter - PinWiggleRoom, center=true);
// Eject pin top 2


Scott
EDIT: Updated LS30_Eject_Pin_Ultimarc.scad to generate two pins instead of just one.
« Last Edit: September 20, 2018, 02:44:23 pm by PL1 »

05SRT4

  • Trade Count: (+5)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 1092
  • Last login:Yesterday at 08:04:24 pm
  • Check out my Pow Pow
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #7 on: September 19, 2018, 07:37:19 am »
Lots of good work here! I have the upgrade and servo stick in hand. Need to find some sample mounting panels and will try your test print.

PL1

  • Global Moderator
  • Trade Count: (+1)
  • Full Member
  • *****
  • Online Online
  • Posts: 9393
  • Last login:Today at 07:06:08 am
  • Designated spam hunter
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #8 on: September 19, 2018, 08:51:23 am »
Lots of good work here! I have the upgrade and servo stick in hand. Need to find some sample mounting panels and will try your test print.
Thanks.   :cheers:

You don't need mounting panels for the test print. (LS30_Test_Print_Ultimarc.scad)

It's just a small cylinder (15.35mm diameter x 11 mm high) that lets you test different values for ShaftDiameter (yellow part) and ThreadedDiameter (red part) without printing a whole handle.
- Test print = 0.44 meters / 1 gram of filament
- Handle     = 3.96 meters / 12 grams of filament




Scott

05SRT4

  • Trade Count: (+5)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 1092
  • Last login:Yesterday at 08:04:24 pm
  • Check out my Pow Pow
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #9 on: September 19, 2018, 04:57:31 pm »
Did a super rough print. The inner diameter has enough play that you can wiggle it back and forth. Im thinking bringing it down to maybe 9.15-9.20 would be enough so it doesn't have much play but still slides on and off.

****JUST NOTICED THE TEST IS DIFFERENT FROM THE ACTUAL ONE****




I printed it at .2 mm layer height, the top part gets a little rough. Im not sure if adding the cap would help smooth it out. Might try doing .1mm layer height to smooth it out but adds another hour to the print.
Also the bottom curve had to much overhang, printing at .1mm might fix that.



I need to get some hardware from the store, printing another one out with other settings. Need more top layers, 2 was not enough.
« Last Edit: September 19, 2018, 05:34:14 pm by 05SRT4 »

PL1

  • Global Moderator
  • Trade Count: (+1)
  • Full Member
  • *****
  • Online Online
  • Posts: 9393
  • Last login:Today at 07:06:08 am
  • Designated spam hunter
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #10 on: September 20, 2018, 01:11:51 pm »
Did a super rough print. The inner diameter has enough play that you can wiggle it back and forth. Im thinking bringing it down to maybe 9.15-9.20 would be enough so it doesn't have much play but still slides on and off.
Yeah, there are lots of little tweaks to the variables that will dial-in these prints for your slicer/firmware-settings/printer.

A firmware setting that I changed on my printer possibly causes it to over-extrude by about 4-6%.

Once you get a good clean print for the handle, it's easy to adjust variables and reprint the smaller pin and handle top prints to fit the handle.

You can probably reduce the "WiggleRoom" variables in the eject pin and handle top OpenSCAD files.

I printed it at .2 mm layer height, the top part gets a little rough. Im not sure if adding the cap would help smooth it out. Might try doing .1mm layer height to smooth it out but adds another hour to the print.
Also the bottom curve had to much overhang, printing at .1mm might fix that.
The overhang on the bottom prints OK here.   :dunno

The cap should help to smooth the top, but you might also want to slightly reduce TopDiameter so you get a circle connecting the inside of the top layer's 8 triangles. (red circle)



If you do that, you might also need to reduce PinDistance. (handle file, line 57)


Scott

lcmgadgets

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 471
  • Last login:July 31, 2023, 01:46:12 pm
  • Can u guess what game this image is from?
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #11 on: October 27, 2018, 06:00:04 pm »
Wowwww! :o
"Godzilla is a warning. A warning to each and every one of us. When mankind falls into conflict with nature, monsters are born."
Professor Hayashida

PL1

  • Global Moderator
  • Trade Count: (+1)
  • Full Member
  • *****
  • Online Online
  • Posts: 9393
  • Last login:Today at 07:06:08 am
  • Designated spam hunter
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #12 on: October 27, 2018, 11:40:12 pm »
Wowwww! :o
Thanks.   :cheers:

I've been working on the design and here's a change that will keep the handle from turning separately from the shaft when the friction between the shaft, handle, and nut isn't high enough.

Instead of using a cylindrical cavity for a socket or nut-driver, use a hexagonal cavity so the handle is the nut-driver for tightening the locknut.
- Use cardboard padded vise-grips to keep the shaft from turning while installing the handle and locknut

A locknut won't easily spin off the threads and with this design change the handle can't turn without also turning the locknut and shaft.

Here's a test print to verify that the hexagonal cavity is a snug fit for the locknut . . .

LS30_Test_Print2_Ultimarc.scad
Code: [Select]
// LS-30 handle for Ultimarc Ikari 12-way Rotary Upgrade
// - Test print 2

// Other prints needed:
// -- Handle
// -- Handle top
// -- Eject pin (2 pins per handle)

// This test print allows you to verify the correct variable values for your specific hardware and your slicer software before you render/export/print the whole handle.

// Hardware tested:
// - Joystick M6 threaded diameter (clears without engaging threads)
// - Locknut (snug fit)


/////////////////////////////
//      Define variables
/////////////////////////////

LocknutDiameter = 11.65;  // Default = 11.55 + wiggle room
    // 10mm flat-to-flat = 11.55mm point-to-point
LocknutHeight = 9;        // Default = 9
ThreadedDiameter = 6.2; // Default = 6.2
// The diameter values may need to be *very slightly* larger to account for the 180-sided polygon used to render circles -- see "undersized holes" at [url]https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Primitive_Solids#cylinder[/url]
$fn=180; // Number of fragments (polygon sides) used to render a circle

/////////////////////////////
//      Make the part
/////////////////////////////

// Make the locknut test layer
difference() {
    hull() {  // Make outer hexagon
    rotate ([0, 0, 0]) translate ([3 + LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight, d = 0.01, center=true);

    rotate ([0, 0, 60]) translate ([3 + LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight, d = 0.01, center=true);

    rotate ([0, 0, 120]) translate ([3 + LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight, d = 0.01, center=true);

    rotate ([0, 0, 180]) translate ([3 + LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight, d = 0.01, center=true);

    rotate ([0, 0, 240]) translate ([3 + LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight, d = 0.01, center=true);

    rotate ([0, 0, 300]) translate ([3 + LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight, d = 0.01, center=true);
    }

    hull() {  // Remove inner hexagon
    translate ([0, 0, 0])
    rotate ([0, 0, 0]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, 0])
    rotate ([0, 0, 60]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, 0])
    rotate ([0, 0, 120]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, 0])
    rotate ([0, 0, 180]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, 0])
    rotate ([0, 0, 240]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, 0])
    rotate ([0, 0, 300]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);
    }
}
//
// Make the thread test layer (red)
difference() {
    color("red") translate([0,0,-1 - LocknutHeight/2]) cylinder(2, d=LocknutDiameter + 6, center=true);
    // Outer cylinder
    translate([0,0,-1 - LocknutHeight/2]) cylinder(LocknutHeight, d=ThreadedDiameter, center=true);
    // Remove threaded hole
}



. . . and here's the updated handle code.

LS30_Handle_Ultimarc.scad
Code: [Select]
// LS-30 handle for Ultimarc Ikari 12-way Rotary Upgrade
// -- Handle

// Other prints needed:
// -- Test print
// -- Test print 2
// -- Handle top
// -- Eject pin (2 pins per handle)

// Required hardware:
// - 6mm locknut

/////////////////////////////
//  Adjustable variables
/////////////////////////////

// Body
    BodyHeight = 35.6; // Default = 35.6
    // Height of the body, not including the dome

// Sides
    SideRoundSphere = 0.7; // Default = 0.7
    // Radius of the side roundover sphere

    LowerBodyDiameter = 31.51; // Default = 31.51
    // Farthest distance from lower point-to-point edge

    UpperBodyDiameter = 29.41; // Default = 29.41
    // Farthest distance from upper point-to-point edge

// Bottom octagon
    LowerRoundSphere = 1.59; // Default = 1.59
    // Radius of the lower roundover sphere

// Top octagon
    UpperRoundSphere = 3.18; // Default = 3.18
    // Radius of the upper roundover sphere

// Spaces to remove from body
    ShaftHeight = 23.8; // Default = 30.4mm - panel thickness. (This formula positions the bottom of the handle 15.6mm above the top of the panel, same as Ikari Warriors.)
    // 11.35 for a 3/4" wood panel (19.05mm)
    // 23.8 for a 1.6mm metal panel with 5mm spacers (6.6mm)
    // Height of the unthreaded shaft cavity   

    ShaftDiameter = 9.35; // Default = 9.35 for a 9mm shaft
    // Diameter of the joystick unthreaded shaft cavity.  This value needs to be *very slightly* larger than the actual joystick shaft diameter to allow for the 180-sided polygon used to render circles -- see "undersized holes" at [url]https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Primitive_Solids#cylinder[/url]

    ThreadedHeight = 6; // Default = 6
    // Height of the thread hole

    ThreadedDiameter = 6.2; // Default = 6.2
    // Outer diameter of the thread hole

    LocknutDiameter = 11.65;  // Default = 11.55 + wiggle room
    // 10mm flat-to-flat = 11.55mm point-to-point
    // (Height is automatically calculated below.)

    PinDistance = 9.3; // Default = 9.3
    // Horizontal distance from handle center to eject pin center
   
    PinDiameter = 4; // Default = 4
    // Diameter of the eject pin body

    TopDiameter = 22.6; // Default = 22.6
    // Hole for removable top.
   
    TopHeight = 2; // Default = 2
    // Hole for removable top.
   
// Number of fragments (polygon sides) used to render a full circle.
    $fn = 180; // Default = 180  Typical range = 6 - 360
    // 6 will render a circular hole as a hexagon, 8 will render a circular hole as an octagon.
    // Lower the number for faster rendering, raise the number for smoother rendering.


/////////////////////////////
//  Non-adjustable variables
/////////////////////////////

// Bottom octagon
    LowerSmallArccosine = SideRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from center of lower small sphere to point of lower octagon [radius*acos(22.5)]

    LowerLargeArccosine = LowerRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from point of lower octagon to center of lower large sphere [radius*acos(22.5)]

    LowerLargeSphereCenter = LowerBodyDiameter/2 - SideRoundSphere + LowerSmallArccosine - LowerLargeArccosine;
    // Rounded octagon point - side (small) sphere radius + distance from center of small sphere to point of octagon - distance from point of octagon to center of large sphere

// Top octagon
    UpperSmallArccosine = SideRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from center of upper small sphere to point of upper octagon [radius*acos(22.5)]

    UpperLargeArccosine = UpperRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from point of upper octagon to center of upper large sphere [radius*acos(22.5)]

    UpperLargeSphereCenter = UpperBodyDiameter/2 - SideRoundSphere + UpperSmallArccosine - UpperLargeArccosine;
    // Rounded octagon point - side (small) sphere radius + distance from center of small sphere to point of octagon - distance from point of octagon to center of large sphere

// Locknut cavity
    LocknutHeight = (BodyHeight - ShaftHeight - ThreadedHeight);
    // Height of the locknut cavity

/////////////////////////////
//  Make the part
/////////////////////////////

// Make the main body
difference(){ // Main body minus holes
    hull() {  // Main body hull
    // Lower roundover large spheres
    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    // Lower side small spheres
    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    // Upper side small spheres
    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere, center = true);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    // Upper roundover large spheres
    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);     

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);
   
    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);
    } // End main body hull

// Holes
color("limegreen") translate ([0, 0, ShaftHeight/2]) cylinder (ShaftHeight, d = ShaftDiameter, center=true); // Make hole for Shaft

color("blue") translate ([0, 0, ShaftHeight+ThreadedHeight/2]) cylinder (ThreadedHeight + .001, d = ThreadedDiameter, center=true); // Make hole for threaded

    color("white") hull() {  // Locknut hexagon hull
    translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2])
    rotate ([0, 0, 0]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2])
    rotate ([0, 0, 60]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2])
    rotate ([0, 0, 120]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2])
    rotate ([0, 0, 180]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2])
    rotate ([0, 0, 240]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2])
    rotate ([0, 0, 300]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);
    }
    // Make hole for locknut

color("red") translate ([0, 0, BodyHeight - TopHeight/2]) cylinder (TopHeight, d = TopDiameter, center=true);
    // Make hole for removable top

color("aqua") translate ([-PinDistance, 0, 1]) cylinder (2.01, d1 = 3.5, d2 = 2, center=true);
    // Eject pin access hole 1

color("aqua") translate ([PinDistance, 0, 1]) cylinder (2.01, d1 = 3.5, d2 = 2, center=true);
    // Eject pin access hole 2

color("purple") translate ([-PinDistance, 0, BodyHeight/2 + 2]) cylinder (BodyHeight, d = PinDiameter, center=true);
    // Eject pin hole 1

color("purple") translate ([PinDistance, 0, BodyHeight/2 + 2]) cylinder (BodyHeight, d = PinDiameter, center=true);
    // Eject pin hole 2
} //End difference main body hull minus holes
//



There are still some details to confirm, but things appear to be on the right track.   ;D


Scott
« Last Edit: October 27, 2018, 11:50:13 pm by PL1 »

smass

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 302
  • Last login:January 09, 2024, 07:46:54 pm
  • Cheapskate Arcade
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #13 on: October 28, 2018, 01:28:29 pm »
Looks great.  Is there a possibility that one of you guys will run off a batch and offer them for sale once this is dialed in? 

PL1

  • Global Moderator
  • Trade Count: (+1)
  • Full Member
  • *****
  • Online Online
  • Posts: 9393
  • Last login:Today at 07:06:08 am
  • Designated spam hunter
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #14 on: October 28, 2018, 10:22:14 pm »
Looks great.  Is there a possibility that one of you guys will run off a batch and offer them for sale once this is dialed in?
Thanks.   :cheers:

I do not plan to sell them.

Haven't discussed it with him yet, but if Andy is interested he can either print them himself or sub-contract to a 3rd party.

If Andy is not interested, another possible option is enabling one or more apps on Thingiverse so a 3rd party can print them.

Has anyone used the apps on Thingiverse to print something?

If you have, which app(s) would you recommend?


Scott

05SRT4

  • Trade Count: (+5)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 1092
  • Last login:Yesterday at 08:04:24 pm
  • Check out my Pow Pow
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #15 on: October 29, 2018, 02:29:09 am »
I have a 3D Hubs account but have yet to get any jobs to print. I am getting a SLA or DLP printer soon and will be curious to see how well these turn out.

PL1

  • Global Moderator
  • Trade Count: (+1)
  • Full Member
  • *****
  • Online Online
  • Posts: 9393
  • Last login:Today at 07:06:08 am
  • Designated spam hunter
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #16 on: February 23, 2019, 02:18:55 am »
The hexagon cavity design works great with an M6-1.0 (coarse thread) nylon-insert locknut like this one;D

As expected, the handle works perfectly as a nutdriver when you use cardboard padded vise-grips to keep the shaft from turning during installation/removal of the handle and locknut.





-------------
Other than the few remaining adjusments listed at the end of this post, the code below should be solid.

If anyone has a 3d printer and the Ultimarc 12-way rotary kit, please test-print a copy to verify.
- Set the ShaftHeight variable (line 40) to 30.4mm minus your panel thickness.

CRITICAL MEASUREMENT: ShaftHeight + ThreadedHeight must be <= 27.8 to allow enough room for the locknut under the top

LS30_Handle_Ultimarc.scad
Code: [Select]
// LS-30 handle for Ultimarc Ikari 12-way Rotary Upgrade
// -- Handle

// Other prints needed:
// -- Test print
// -- Test print 2
// -- Handle top
// -- Eject pin (2 pins per handle)

// Required hardware:
// - M6 locknut (M6-1.0mm thread)

/////////////////////////////
//  Adjustable variables
/////////////////////////////

// Body
    BodyHeight = 35.6; // Default = 35.6
    // Height of the body, not including the dome

// Sides
    SideRoundSphere = 0.7; // Default = 0.7
    // Radius of the side roundover sphere

    LowerBodyDiameter = 31.51; // Default = 31.51
    // Farthest distance from lower point-to-point edge

    UpperBodyDiameter = 29.41; // Default = 29.41
    // Farthest distance from upper point-to-point edge

// Bottom octagon
    LowerRoundSphere = 1.59; // Default = 1.59
    // Radius of the lower roundover sphere

// Top octagon
    UpperRoundSphere = 3.18; // Default = 3.18
    // Radius of the upper roundover sphere

// Spaces to remove from body
    ShaftHeight = 21.8; // Default = 30.4mm - panel thickness. (This formula positions the bottom of the handle 15.6mm above the top of the panel, same as Ikari Warriors.)
    // 11.35 for a 3/4" wood panel (19.05mm)
    // 21.8 for a 1.6mm metal panel with 7mm spacers (8.6mm)
    // CRITICAL MEASUREMENT: ShaftHeight + ThreadedHeight must be <= 27.8 to allow enough room for the locknut under the top
    // Height of the unthreaded shaft cavity

    ShaftDiameter = 9.35; // Default = 9.35 for a 9mm shaft
    // Diameter of the joystick unthreaded shaft cavity.  This value needs to be *very slightly* larger than the actual joystick shaft diameter to allow for the 180-sided polygon used to render circles -- see "undersized holes" at [url]https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Primitive_Solids#cylinder[/url]

    ThreadedHeight = 6; // Default = 6
    // CRITICAL MEASUREMENT: ShaftHeight + ThreadedHeight must be <= 27.8 to allow enough room for the locknut under the top
    // Height of the thread hole

    ThreadedDiameter = 6.2; // Default = 6.2
    // Outer diameter of the thread hole

    LocknutDiameter = 11.65;  // Default = 11.55 + wiggle room
    // 10mm flat-to-flat = 11.55mm point-to-point
    // (Height is automatically calculated below.)

    PinDistance = 9; // Default = 9
    // Horizontal distance from handle center to eject pin center
   
    PinDiameter = 4; // Default = 4
    // Diameter of the eject pin body

    TopDiameter = 22.6; // Default = 22.6
    // Hole for removable top.
   
    TopHeight = 2; // Default = 2
    // Hole for removable top.
   
// Number of fragments (polygon sides) used to render a full circle.
    $fn = 180; // Default = 180  Typical range = 6 - 360
    // 6 will render a circular hole as a hexagon, 8 will render a circular hole as an octagon.
    // Lower the number for faster rendering, raise the number for smoother rendering.


/////////////////////////////
//  Non-adjustable variables
/////////////////////////////

// Bottom octagon
    LowerSmallArccosine = SideRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from center of lower small sphere to point of lower octagon [radius*acos(22.5)]

    LowerLargeArccosine = LowerRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from point of lower octagon to center of lower large sphere [radius*acos(22.5)]

    LowerLargeSphereCenter = LowerBodyDiameter/2 - SideRoundSphere + LowerSmallArccosine - LowerLargeArccosine;
    // Rounded octagon point - side (small) sphere radius + distance from center of small sphere to point of octagon - distance from point of octagon to center of large sphere

// Top octagon
    UpperSmallArccosine = SideRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from center of upper small sphere to point of upper octagon [radius*acos(22.5)]

    UpperLargeArccosine = UpperRoundSphere * 1.0823922002923939687994464107328;
    // Calculates distance from point of upper octagon to center of upper large sphere [radius*acos(22.5)]

    UpperLargeSphereCenter = UpperBodyDiameter/2 - SideRoundSphere + UpperSmallArccosine - UpperLargeArccosine;
    // Rounded octagon point - side (small) sphere radius + distance from center of small sphere to point of octagon - distance from point of octagon to center of large sphere

// Locknut cavity
    LocknutHeight = (BodyHeight - ShaftHeight - ThreadedHeight);
    // Height of the locknut cavity

/////////////////////////////
//  Make the part
/////////////////////////////

// Make the main body
difference(){ // Main body minus holes
    hull() {  // Main body hull
    // Lower roundover large spheres
    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([LowerLargeSphereCenter, 0, LowerRoundSphere/2]) sphere (r = LowerRoundSphere);     

    // Lower side small spheres
    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, LowerRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([-SideRoundSphere + LowerBodyDiameter/2, 0, LowerRoundSphere/2]) sphere (r = SideRoundSphere);

    // Upper side small spheres
    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere, center = true);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([-SideRoundSphere + UpperBodyDiameter/2, 0, - UpperRoundSphere/2]) sphere (r = SideRoundSphere);

    // Upper roundover large spheres
    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 22.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 67.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 112.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 157.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);     

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 202.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 247.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);
   
    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 292.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);

    translate ([0, 0, BodyHeight - UpperRoundSphere/2])
    rotate ([0, 0, 337.5]) translate ([UpperLargeSphereCenter, 0, - UpperRoundSphere/2]) sphere (r = UpperRoundSphere);
    } // End main body hull

// Holes
color("limegreen") translate ([0, 0, ShaftHeight/2]) cylinder (ShaftHeight, d = ShaftDiameter, center=true); // Make hole for Shaft

color("blue") translate ([0, 0, ShaftHeight+ThreadedHeight/2]) cylinder (ThreadedHeight + .001, d = ThreadedDiameter, center=true); // Make hole for threaded

color("white") hull() {  // Locknut hexagon hull
    translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2])
    rotate ([0, 0, 0]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2])
    rotate ([0, 0, 60]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2])
    rotate ([0, 0, 120]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2])
    rotate ([0, 0, 180]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2])
    rotate ([0, 0, 240]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);

    translate ([0, 0, ShaftHeight + ThreadedHeight + LocknutHeight/2])
    rotate ([0, 0, 300]) translate ([LocknutDiameter/2, 0, 0]) cylinder (LocknutHeight + 0.01, d = 0.01, center=true);
    }
    // Make hole for locknut

color("red") translate ([0, 0, BodyHeight - TopHeight/2]) cylinder (TopHeight, d = TopDiameter, center=true);
    // Make hole for removable top

color("aqua") translate ([0, -PinDistance, 1]) cylinder (2.01, d1 = 3.5, d2 = 2, center=true);
    // Eject pin access hole 1

color("aqua") translate ([0, PinDistance, 1]) cylinder (2.01, d1 = 3.5, d2 = 2, center=true);
    // Eject pin access hole 2

color("purple") translate ([0, -PinDistance, BodyHeight/2 + 2]) cylinder (BodyHeight, d = PinDiameter, center=true);
    // Eject pin hole 1

color("purple") translate ([0, PinDistance, BodyHeight/2 + 2]) cylinder (BodyHeight, d = PinDiameter, center=true);
    // Eject pin hole 2
} //End difference main body hull minus holes
//

Things left to do:
- Reposition the eject pins Done
- Re-size the removable top diameter so the handle's top layer doesn't have those 8 points
- Review/clarify the code documentation
- Write a step-by-step tutorial
- Compile handle .STLs for common panel thicknesses (3/4", 5/8", 1/2", 18mm, 15mm, and 12mm)
-- Are these the most commonly available metric lumber sizes?  Any other sizes?
- Post everything on Thingiverse (the handle .STLs are too large to upload here  :( )


Scott
« Last Edit: February 23, 2019, 06:09:33 pm by PL1 »

Doverben

  • Trade Count: (0)
  • Jr. Member
  • **
  • Offline Offline
  • Posts: 4
  • Last login:January 07, 2023, 11:57:26 am
  • Current build: SU cab w/ 6 swappable CPs
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #17 on: April 01, 2019, 02:15:49 pm »
I'm about to place an Ultimarc order for a pair of J-Stiks and the 12-way Rotary kits for J-Stik, so I am also very interested in either purchasing a set of finished handles from a 3rd party, or providing specs to a company that can print the parts out.

I've been lurking back and forth in this thread for a little while, and am looking forward to the finished product. Is there an update to this project?

PL1

  • Global Moderator
  • Trade Count: (+1)
  • Full Member
  • *****
  • Online Online
  • Posts: 9393
  • Last login:Today at 07:06:08 am
  • Designated spam hunter
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #18 on: April 01, 2019, 06:09:29 pm »
I'm about to place an Ultimarc order for a pair of J-Stiks and the 12-way Rotary kits for J-Stik, so I am also very interested in either purchasing a set of finished handles from a 3rd party, or providing specs to a company that can print the parts out.

I've been lurking back and forth in this thread for a little while, and am looking forward to the finished product. Is there an update to this project?
Thanks for your interest and encouragement.   :cheers:

There isn't much left to do, but I've been a bit sidetracked between projects around the house, helping Saint with the new server to-do list :) and dealing with a relatively high-volume three-week-long spam-account-creation attack.   :angry:

I hope to find better default values for the TopDiameter, TopWiggleRoom, and TopTaper variables in the next week or two.

Once those are dialed-in, the rest should fall into place pretty quickly.   ;D


Scott

Doverben

  • Trade Count: (0)
  • Jr. Member
  • **
  • Offline Offline
  • Posts: 4
  • Last login:January 07, 2023, 11:57:26 am
  • Current build: SU cab w/ 6 swappable CPs
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #19 on: April 03, 2019, 01:57:42 pm »
Thank you for the prompt reply Scott, and I really appreciate that you're still finding time to devote to this project.  We all look forward to the final solution.  :applaud:

My Ultimarc order should be in next week, so let me know if there's anything I can do to help.  :)

Stealthlurker

  • Trade Count: (0)
  • Jr. Member
  • **
  • Offline Offline
  • Posts: 1
  • Last login:May 21, 2019, 02:55:57 pm
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #20 on: May 21, 2019, 02:02:52 pm »
Just installed a J-stick with rotary mod last night. Super excited to see this project! Would love a handle or two!

PL1

  • Global Moderator
  • Trade Count: (+1)
  • Full Member
  • *****
  • Online Online
  • Posts: 9393
  • Last login:Today at 07:06:08 am
  • Designated spam hunter
Re: 3d printed LS-30 handle for the Ultimarc Ikari 12-way Rotary Upgrade
« Reply #21 on: May 21, 2019, 02:30:28 pm »
Just installed a J-stick with rotary mod last night. Super excited to see this project!
Thanks for your interest and encouragement.   :cheers:

Would love a handle or two!
Print as many as you'd like.   ;)


Scott