/*
* Trackball
*
* Copyright (c) 2022 - 2023 Thomas Buck (thomas@xythobuz.de)
* Philipp Schönberger (mail@phschoen.de)
*
* Required parts:
* - 1x Raspberry Pi Pico
* - 4x Cherry MX compatible switches and keycaps
* - 1x Billard ball, diameter 38mm
* - 3x Si3N4 static bearing balls, diameter 3mm
* - 1x PMW3360 sensor with breakout board
* - 8x M2 screw, length 5mm
* - 8x M2 heat melt insert, length 4mm
*
* For the PMW3360 breakout board get this:
* https://github.com/jfedor2/pmw3360-breakout
*
* This program 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.
*
* This program 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.
*
* See .
*/
include; // need include since the parameters are in there
include ; // need include since the parameters are in there
use;
use;
use;
use;
use;
use;
use;
include;
translate([$t*assembly_dist,$t*-assembly_dist,0])
top_hand_wrest();
trackball_top();
translate([0,0,-$t*assembly_dist])
trackball_bot();
// %translate([-13,38,5-trackball_dia/2])
// scale(150)
// rotate([0,0,-133])
// import("external/mouse_scan_v1.stl");
module trackball_bot()
{
difference() {
color("green")
trans_bot_of_top_part()
translate([0,0,-wall])
linear_extrude(wall)
{
hull()
projection() {
trackball_top();
}
projection() {
top_hand_wrest();
}
}
trackball_bot_screw_cuts();
}
}
module trackball_bot_screw_cuts(e=2)
{
pos= [
// offset angle
[ trackball_dia/2 + 15, 52 + 15 ],
[ trackball_dia/2 + 15, 52 - 40 ],
[ trackball_dia/2 + 15, 52 - 15 + 180 ],
[ trackball_dia/2 + 15, 52 + 40 + 180 ],
[ trackball_dia/2 + 75, 52 - 90 -10],
[ trackball_dia/2 + 75, 52 - 90 +10],
];
for(p = pos)
rotate([0,0,p[1]])
translate([p[0],0,0])
translate([0,0,7-$e*2])
trans_bot_of_top_part()
rotate([0,180,0])
{
m3_screw_insert_cut(8);
}
}
module trackball_top()
{
if (draw_ball_bearing_holder)
%ball_and_bearing_holder();
difference()
{
hull()
{
intersection_top_part(is_wristrest = false)
trackball_top_hull(with_bot_cuts=true);
trans_bot_of_top_part()
linear_extrude($e)
projection() {
intersection_top_part(is_wristrest = false)
trackball_top_hull(with_bot_cuts=true);
}
}
top_body_cutouts();
}
}
module intersection_top_part(is_wristrest = false)
{
intersection()
{
rotate([0,0,-38])
translate([37.1,-50,-50])
trans_bot_of_top_part()
if(is_wristrest == true)
cube([100,200,200]);
else
translate([-100,0,0])
cube([100,200,200]);
children();
}
}
module m3_screw_insert_cut(l=20)
{
// screw thread cutout
color("silver")
cylinder(d=3,h=50);
// insert cutout itself
color("gold")
cylinder(d=4.6+$c*2,h=7);
// screw head cutout for sliding in
translate([0,0,l])
color("silver")
cylinder(d=6+$c*2,h=50);
// insert iself
// % color("gold")
// cylinder(d=4.6,h=5.7);
}
module wrest_screw_cutout()
{
for(i=[1,-1])
rotate([0,0,-38])
translate([31,i*15,14])
trans_bot_of_top_part()
rotate([0,20,0])
rotate([0,90,0])
{
m3_screw_insert_cut(20);
}
}
module top_hand_wrestv1()
{
difference()
{
intersection_top_part(is_wristrest = true)
rotate([0,0,-38])
translate([60,0,0])
trans_bot_of_top_part()
intersection()
{
scale([3.5,1.5,1])
cylinder(r = 20, h = trackball_dia+17);
translate([15,0,20-trackball_dia/2])
rotate([0,30,0])
scale([1.3,1.4,1])
sphere(d=70);
}
// screw cutout for attaching the wrist rest to the top part
wrest_screw_cutout();
// screw cutouts for the bottom plate
translate([0,0,-$e])
trackball_bot_screw_cuts(e=0);
// pi pico cutout
rotate([0,0,50])
trans_bot_of_top_part()
translate([3,-80,3])
{
%if(draw_pico) pico_wrap();
pico_cutout(20);
}
}
}
module top_hand_wrest()
{
difference()
{
intersection_top_part(is_wristrest = true)
rotate([0,0,-38])
translate([60,0,0])
trans_bot_of_top_part()
intersection() {
translate([-200,-200,0])
cube([400,400,100]);
minkowski() {
intersection()
{
scale([3.5,1.5,1])
cylinder(r = 20, h = trackball_dia+17);
translate([15,0,20-trackball_dia/2])
rotate([0,30,0])
scale([1.3,1.4,1])
sphere(d=70);
}
sphere(r = 3);
}
}
// screw cutout for attaching the wrist rest to the top part
wrest_screw_cutout();
// screw cutouts for the bottom plate
translate([0,0,-$e])
trackball_bot_screw_cuts(e=0);
// pi pico cutout
rotate([0,0,50])
trans_bot_of_top_part()
translate([3,-80,3])
{
%if(draw_pico) pico_wrap();
pico_cutout(20);
}
}
}
module pico_cutout(extra)
{
translate([-pico_w / 2, -pico_l / 2, -extra]) {
// pcb cutout
cube([pico_w, pico_l, 4 + extra]);
// screw cutouts
for (x = [0, pico_hole_d_x])
for (y = [0, pico_hole_d_y])
translate([pico_hole_x + x, pico_hole_y + y, extra])
cylinder(d = pico_hole_d, h = pico_d + 2+5);
// cable channels
translate([pico_w/2-9/2,pico_l-10,0])
cube([9, trackball_dia+10, 4 + extra+2]);
}
}
module top_body_cutouts()
{
// space for roller holder
bearing_rot_trans()
translate([0,0,-bearing_h])
cylinder(d = bearing_mount_dia + 1, h = trackball_dia / 2 + bearing_h);
// room for ball itself
sphere($fn = $fn * 2, d = trackball_dia + $c * 2 + 4);
// grub screws for the bearing holder
bearing_rot_trans()
rotate([0,-90,90])
translate([-bearing_h+4, 0, 0])
{
cylinder(d = grub_screw_dia, h = trackball_dia);
translate([0, 0, bearing_mount_grub_screw_l]) // outside of wall
translate([0, 0, bearing_mount_dia/2 +wall/2]) // outside of wall
cylinder(d = grub_channel_dia, h = trackball_dia);
}
// sensor lens
sensor_cutout();
%if(draw_sensor) sensor_pos();
// switch cutouts
//translate([0, 0, trackball_dia / 2 + ball_h])
switch_rot_trans(0)
translate([10,10,0])
{
// switch cutout itself
mx_switch_cutout(mx_co_depth);
%if(draw_switches)
translate([0,0,10])
mx_switch();
}
switch_rot_trans(0,false)
translate([10,10,0])
{
// cable channel
rotate([-40,0,0])
rotate([0,180,0])
cylinder(d=3,h=trackball_dia);
}
// led ring
translate([0,0,-trackball_dia/2])
{
led_ring(cutout=true, extra = trackball_dia/2);
%if(draw_led) led_ring();
}
// screw cutouts for the wrist rest
wrest_screw_cutout();
// screw cutouts for the bottom plate
translate([0,0,-$e])
trackball_bot_screw_cuts(e=0);
// pico cutout
rotate([0,0,50])
trans_bot_of_top_part()
translate([3,-80,3])
{
pico_cutout(20);
pico_cutout(20);
}
// usb cutout
rotate([0,0,180+50])
trans_bot_of_top_part()
translate([0,-trackball_dia/2-8,2])
{
%if(draw_usb_c)usb_c();
usb_c_cutout();
}
}
module switch_rot_trans(r,x_rot=true)
{
for ( i = [0:len(sw)-1] )
{
rotate([0,0,sw[i][0][2]])
translate(sw[i][1])
rotate([90+(x_rot ? sw[i][0][0] : 0),0,sw[i][0][1]])
translate([-sw_mount_w/2 - r, -sw_mount_w/2 - r, -r - r/2])
children();
}
}
module trans_bot_of_top_part()
{
translate([0, 0, -trackball_dia / 2 -11])
children();
}
module trackball_top_hull(with_bot_cuts=true)
{
difference() {
color("orange")
union(){
hull() {
// bearing holder cylinders
bearing_rot_trans()
bearing_holder_mount();
// base circle
trans_bot_of_top_part()
cylinder(d = base_dia, h = $e);
// switch
switch_rot_trans(sw_mount_r)
translate([0,0,sw_mount_r*2])
fully_rounded_cube([sw_mount_w + sw_mount_r*2,
sw_mount_w + sw_mount_r*2,
mx_co_depth], sw_mount_r);
}
}
}
}