Browse Source

some work on firmware and 3d design

Thomas Buck 1 year ago
parent
commit
70ae088d4c

+ 7
- 0
firmware/include/pmw3360.h View File

@@ -5,7 +5,14 @@
5 5
 #ifndef __PMW3360_H__
6 6
 #define __PMW3360_H__
7 7
 
8
+struct pmw_motion {
9
+    bool motion;
10
+    int32_t delta_x;
11
+    int32_t delta_y;
12
+};
13
+
8 14
 int pmw_init(void);
15
+struct pmw_motion pmw_get(void);
9 16
 
10 17
 /*
11 18
  * 0x00: 100 cpi (minimum cpi)

+ 5
- 0
firmware/include/usb_hid.h View File

@@ -5,6 +5,11 @@
5 5
 #ifndef __USB_HID_H__
6 6
 #define __USB_HID_H__
7 7
 
8
+struct usb_hid_mouse {
9
+    int32_t delta_x;
10
+    int32_t delta_y;
11
+};
12
+
8 13
 void hid_task(void);
9 14
 
10 15
 #endif // __USB_HID_H__

+ 2
- 0
firmware/include/util.h View File

@@ -8,6 +8,8 @@
8 8
 void heartbeat_init(void);
9 9
 void heartbeat_run(void);
10 10
 
11
+int32_t convert_two_complement(int32_t b);
12
+
11 13
 bool str_startswith(const char *str, const char *start);
12 14
 
13 15
 void reset_to_bootloader(void);

+ 29
- 12
firmware/src/pmw3360.c View File

@@ -31,6 +31,9 @@
31 31
 #error PMW3360 API requires a board with SPI pins
32 32
 #endif
33 33
 
34
+static volatile int32_t delta_x = 0, delta_y = 0;
35
+static volatile bool mouse_motion = false;
36
+
34 37
 #ifdef PMW_IRQ_COUNTERS
35 38
 static uint64_t pmw_irq_count_all = 0;
36 39
 static uint64_t pmw_irq_count_motion = 0;
@@ -57,6 +60,26 @@ void pmw_print_status(void) {
57 60
 #endif // PMW_IRQ_COUNTERS
58 61
 }
59 62
 
63
+struct pmw_motion pmw_get(void) {
64
+    struct pmw_motion r;
65
+    r.motion = mouse_motion;
66
+    r.delta_x = 0;
67
+    r.delta_y = 0;
68
+
69
+    if (r.motion) {
70
+        gpio_set_irq_enabled(PMW_MOTION_PIN, GPIO_IRQ_EDGE_FALL, false);
71
+
72
+        r.delta_x = delta_x;
73
+        r.delta_y = delta_y;
74
+        delta_x = 0;
75
+        delta_y = 0;
76
+
77
+        gpio_set_irq_enabled(PMW_MOTION_PIN, GPIO_IRQ_EDGE_FALL, true);
78
+    }
79
+
80
+    return r;
81
+}
82
+
60 83
 static inline void pmw_cs_select() {
61 84
     asm volatile("nop \n nop \n nop");
62 85
     gpio_put(PICO_DEFAULT_SPI_CSN_PIN, 0); // Active low
@@ -225,16 +248,6 @@ static void pmw_spi_init(void) {
225 248
     bi_decl(bi_1pin_with_name(PICO_DEFAULT_SPI_CSN_PIN, "SPI CS"));
226 249
 }
227 250
 
228
-// TODO
229
-int16_t delta_x = 0, delta_y = 0;
230
-int convTwosComp(int b){
231
-    //Convert from 2's complement
232
-    if(b & 0x8000){
233
-        b = -1 * ((b ^ 0xffff) + 1);
234
-    }
235
-    return b;
236
-}
237
-
238 251
 static void pmw_handle_interrupt(void) {
239 252
     struct pmw_motion_report motion_report = pmw_motion_read();
240 253
 
@@ -265,8 +278,12 @@ static void pmw_handle_interrupt(void) {
265 278
     }
266 279
 #endif // PMW_IRQ_COUNTERS
267 280
 
268
-    delta_x += convTwosComp(motion_report.delta_x_l | (motion_report.delta_x_h << 8));
269
-    delta_y += convTwosComp(motion_report.delta_y_l | (motion_report.delta_y_h << 8));
281
+    uint16_t delta_x_raw = motion_report.delta_x_l | (motion_report.delta_x_h << 8);
282
+    uint16_t delta_y_raw = motion_report.delta_y_l | (motion_report.delta_y_h << 8);
283
+
284
+    delta_x += convert_two_complement(delta_x_raw);
285
+    delta_y += convert_two_complement(delta_y_raw);
286
+    mouse_motion = true;
270 287
 }
271 288
 
272 289
 static void pmw_motion_irq(void) {

+ 0
- 3
firmware/src/usb_hid.c View File

@@ -30,9 +30,6 @@
30 30
 #include "usb_descriptors.h"
31 31
 #include "usb_hid.h"
32 32
 
33
-// TODO
34
-extern int16_t delta_x, delta_y;
35
-
36 33
 static void send_hid_report(uint8_t report_id, uint32_t btn) {
37 34
     // skip if hid is not ready yet
38 35
     if ( !tud_hid_ready() ) return;

+ 7
- 0
firmware/src/util.c View File

@@ -41,6 +41,13 @@ bool str_startswith(const char *str, const char *start) {
41 41
     return (strncmp(str, start, l) == 0);
42 42
 }
43 43
 
44
+int32_t convert_two_complement(int32_t b) {
45
+    if (b & 0x8000) {
46
+        b = -1 * ((b ^ 0xffff) + 1);
47
+    }
48
+    return b;
49
+}
50
+
44 51
 void reset_to_bootloader(void) {
45 52
 #ifdef PICO_DEFAULT_LED_PIN
46 53
     reset_usb_boot(1 << PICO_DEFAULT_LED_PIN, 0);

+ 0
- 431
hardware/external/threads.scad View File

@@ -1,431 +0,0 @@
1
-/*
2
- * ISO-standard metric threads, following this specification:
3
- *          http://en.wikipedia.org/wiki/ISO_metric_screw_thread
4
- *
5
- * Copyright 2022 Dan Kirshner - dan_kirshner@yahoo.com
6
- * This program is free software: you can redistribute it and/or modify
7
- * it under the terms of the GNU General Public License as published by
8
- * the Free Software Foundation, either version 3 of the License, or
9
- * (at your option) any later version.
10
- *
11
- * This program is distributed in the hope that it will be useful,
12
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
- * GNU General Public License for more details.
15
- *
16
- * See <http://www.gnu.org/licenses/>.
17
- *
18
- * Version 2.7.  2022-02-27  Increase minimum thread segments.
19
- * Version 2.6.  2021-05-16  Contributed patches for leadin (thanks,
20
-                             jeffery.spirko@tamucc.edu) and aligning thread
21
-                             "facets" (triangulation) with base cylinder
22
-                             (thanks, rambetter@protonmail.com).
23
- * Version 2.5.  2020-04-11  Leadin option works for internal threads.
24
- * Version 2.4.  2019-07-14  Add test option - do not render threads.
25
- * Version 2.3.  2017-08-31  Default for leadin: 0 (best for internal threads).
26
- * Version 2.2.  2017-01-01  Correction for angle; leadfac option.  (Thanks to
27
- *                           Andrew Allen <a2intl@gmail.com>.)
28
- * Version 2.1.  2016-12-04  Chamfer bottom end (low-z); leadin option.
29
- * Version 2.0.  2016-11-05  Backwards compatibility (earlier OpenSCAD) fixes.
30
- * Version 1.9.  2016-07-03  Option: tapered.
31
- * Version 1.8.  2016-01-08  Option: (non-standard) angle.
32
- * Version 1.7.  2015-11-28  Larger x-increment - for small-diameters.
33
- * Version 1.6.  2015-09-01  Options: square threads, rectangular threads.
34
- * Version 1.5.  2015-06-12  Options: thread_size, groove.
35
- * Version 1.4.  2014-10-17  Use "faces" instead of "triangles" for polyhedron
36
- * Version 1.3.  2013-12-01  Correct loop over turns -- don't have early cut-off
37
- * Version 1.2.  2012-09-09  Use discrete polyhedra rather than linear_extrude ()
38
- * Version 1.1.  2012-09-07  Corrected to right-hand threads!
39
- */
40
-
41
-// Examples.
42
-//
43
-// Standard M8 x 1.
44
-// metric_thread (diameter=8, pitch=1, length=4);
45
-
46
-// Square thread.
47
-// metric_thread (diameter=8, pitch=1, length=4, square=true);
48
-
49
-// Non-standard: long pitch, same thread size.
50
-//metric_thread (diameter=8, pitch=4, length=4, thread_size=1, groove=true);
51
-
52
-// Non-standard: 20 mm diameter, long pitch, square "trough" width 3 mm,
53
-// depth 1 mm.
54
-//metric_thread (diameter=20, pitch=8, length=16, square=true, thread_size=6,
55
-//               groove=true, rectangle=0.333);
56
-
57
-// English: 1/4 x 20.
58
-//english_thread (diameter=1/4, threads_per_inch=20, length=1);
59
-
60
-// Tapered.  Example -- pipe size 3/4" -- per:
61
-// http://www.engineeringtoolbox.com/npt-national-pipe-taper-threads-d_750.html
62
-// english_thread (diameter=1.05, threads_per_inch=14, length=3/4, taper=1/16);
63
-
64
-// Thread for mounting on Rohloff hub.
65
-//difference () {
66
-//   cylinder (r=20, h=10, $fn=100);
67
-//
68
-//   metric_thread (diameter=34, pitch=1, length=10, internal=true, n_starts=6);
69
-//}
70
-
71
-
72
-// ----------------------------------------------------------------------------
73
-function segments (diameter) = min (150, max (ceil (diameter*6), 25));
74
-
75
-
76
-// ----------------------------------------------------------------------------
77
-// diameter -    outside diameter of threads in mm. Default: 8.
78
-// pitch    -    thread axial "travel" per turn in mm.  Default: 1.
79
-// length   -    overall axial length of thread in mm.  Default: 1.
80
-// internal -    true = clearances for internal thread (e.g., a nut).
81
-//               false = clearances for external thread (e.g., a bolt).
82
-//               (Internal threads should be "cut out" from a solid using
83
-//               difference ()).  Default: false.
84
-// n_starts -    Number of thread starts (e.g., DNA, a "double helix," has
85
-//               n_starts=2).  See wikipedia Screw_thread.  Default: 1.
86
-// thread_size - (non-standard) axial width of a single thread "V" - independent
87
-//               of pitch.  Default: same as pitch.
88
-// groove      - (non-standard) true = subtract inverted "V" from cylinder
89
-//                (rather thanadd protruding "V" to cylinder).  Default: false.
90
-// square      - true = square threads (per
91
-//               https://en.wikipedia.org/wiki/Square_thread_form).  Default:
92
-//               false.
93
-// rectangle   - (non-standard) "Rectangular" thread - ratio depth/(axial) width
94
-//               Default: 0 (standard "v" thread).
95
-// angle       - (non-standard) angle (deg) of thread side from perpendicular to
96
-//               axis (default = standard = 30 degrees).
97
-// taper       - diameter change per length (National Pipe Thread/ANSI B1.20.1
98
-//               is 1" diameter per 16" length). Taper decreases from 'diameter'
99
-//               as z increases.  Default: 0 (no taper).
100
-// leadin      - 0 (default): no chamfer; 1: chamfer (45 degree) at max-z end;
101
-//               2: chamfer at both ends, 3: chamfer at z=0 end.
102
-// leadfac     - scale of leadin chamfer length (default: 1.0 = 1/2 thread).
103
-// test        - true = do not render threads (just draw "blank" cylinder).
104
-//               Default: false (draw threads).
105
-module metric_thread (diameter=8, pitch=1, length=1, internal=false, n_starts=1,
106
-                      thread_size=-1, groove=false, square=false, rectangle=0,
107
-                      angle=30, taper=0, leadin=0, leadfac=1.0, test=false)
108
-{
109
-   // thread_size: size of thread "V" different than travel per turn (pitch).
110
-   // Default: same as pitch.
111
-   local_thread_size = thread_size == -1 ? pitch : thread_size;
112
-   local_rectangle = rectangle ? rectangle : 1;
113
-
114
-   n_segments = segments (diameter);
115
-   h = (test && ! internal) ? 0 : (square || rectangle) ? local_thread_size*local_rectangle/2 : local_thread_size / (2 * tan(angle));
116
-
117
-   h_fac1 = (square || rectangle) ? 0.90 : 0.625;
118
-
119
-   // External thread includes additional relief.
120
-   h_fac2 = (square || rectangle) ? 0.95 : 5.3/8;
121
-
122
-   tapered_diameter = diameter - length*taper;
123
-
124
-   difference () {
125
-      union () {
126
-         if (! groove) {
127
-            if (! test) {
128
-               metric_thread_turns (diameter, pitch, length, internal, n_starts,
129
-                                    local_thread_size, groove, square, rectangle, angle,
130
-                                    taper);
131
-            }
132
-         }
133
-
134
-         difference () {
135
-
136
-            // Solid center, including Dmin truncation.
137
-            if (groove) {
138
-               cylinder (r1=diameter/2, r2=tapered_diameter/2,
139
-                         h=length, $fn=n_segments);
140
-            } else if (internal) {
141
-               cylinder (r1=diameter/2 - h*h_fac1, r2=tapered_diameter/2 - h*h_fac1,
142
-                         h=length, $fn=n_segments);
143
-            } else {
144
-
145
-               // External thread.
146
-               cylinder (r1=diameter/2 - h*h_fac2, r2=tapered_diameter/2 - h*h_fac2,
147
-                         h=length, $fn=n_segments);
148
-            }
149
-
150
-            if (groove) {
151
-               if (! test) {
152
-                  metric_thread_turns (diameter, pitch, length, internal, n_starts,
153
-                                       local_thread_size, groove, square, rectangle,
154
-                                       angle, taper);
155
-               }
156
-            }
157
-         }
158
-
159
-         // Internal thread lead-in: take away from external solid.
160
-         if (internal) {
161
-
162
-            // "Negative chamfer" z=0 end if leadin is 2 or 3.
163
-            if (leadin == 2 || leadin == 3) {
164
-
165
-               // Fixes by jeffery.spirko@tamucc.edu.
166
-               cylinder (r1=diameter/2 - h + h*h_fac1*leadfac,
167
-                         r2=diameter/2 - h,
168
-                         h=h*h_fac1*leadfac, $fn=n_segments);
169
-               /*
170
-               cylinder (r1=diameter/2,
171
-                         r2=diameter/2 - h*h_fac1*leadfac,
172
-                         h=h*h_fac1*leadfac, $fn=n_segments);
173
-               */
174
-            }
175
-
176
-            // "Negative chamfer" z-max end if leadin is 1 or 2.
177
-            if (leadin == 1 || leadin == 2) {
178
-               translate ([0, 0, length + 0.05 - h*h_fac1*leadfac]) {
179
-
180
-                  cylinder (r1=tapered_diameter/2 - h,
181
-                            h=h*h_fac1*leadfac,
182
-                            r2=tapered_diameter/2 - h + h*h_fac1*leadfac,
183
-                            $fn=n_segments);
184
-                  /*
185
-                  cylinder (r1=tapered_diameter/2 - h*h_fac1*leadfac,
186
-                            h=h*h_fac1*leadfac,
187
-                            r2=tapered_diameter/2,
188
-                            $fn=n_segments);
189
-                  */
190
-               }
191
-            }
192
-         }
193
-      }
194
-
195
-      if (! internal) {
196
-
197
-         // Chamfer z=0 end if leadin is 2 or 3.
198
-         if (leadin == 2 || leadin == 3) {
199
-            difference () {
200
-               cylinder (r=diameter/2 + 1, h=h*h_fac1*leadfac, $fn=n_segments);
201
-
202
-               cylinder (r2=diameter/2, r1=diameter/2 - h*h_fac1*leadfac, h=h*h_fac1*leadfac,
203
-                         $fn=n_segments);
204
-            }
205
-         }
206
-
207
-         // Chamfer z-max end if leadin is 1 or 2.
208
-         if (leadin == 1 || leadin == 2) {
209
-            translate ([0, 0, length + 0.05 - h*h_fac1*leadfac]) {
210
-               difference () {
211
-                  cylinder (r=diameter/2 + 1, h=h*h_fac1*leadfac, $fn=n_segments);
212
-
213
-                  cylinder (r1=tapered_diameter/2, r2=tapered_diameter/2 - h*h_fac1*leadfac, h=h*h_fac1*leadfac,
214
-                            $fn=n_segments);
215
-               }
216
-            }
217
-         }
218
-      }
219
-   }
220
-}
221
-
222
-
223
-// ----------------------------------------------------------------------------
224
-// Input units in inches.
225
-// Note: units of measure in drawing are mm!
226
-module english_thread (diameter=0.25, threads_per_inch=20, length=1,
227
-                      internal=false, n_starts=1, thread_size=-1, groove=false,
228
-                      square=false, rectangle=0, angle=30, taper=0, leadin=0,
229
-                      leadfac=1.0, test=false)
230
-{
231
-   // Convert to mm.
232
-   mm_diameter = diameter*25.4;
233
-   mm_pitch = (1.0/threads_per_inch)*25.4;
234
-   mm_length = length*25.4;
235
-
236
-   echo (str ("mm_diameter: ", mm_diameter));
237
-   echo (str ("mm_pitch: ", mm_pitch));
238
-   echo (str ("mm_length: ", mm_length));
239
-   metric_thread (mm_diameter, mm_pitch, mm_length, internal, n_starts,
240
-                  thread_size, groove, square, rectangle, angle, taper, leadin,
241
-                  leadfac, test);
242
-}
243
-
244
-// ----------------------------------------------------------------------------
245
-module metric_thread_turns (diameter, pitch, length, internal, n_starts,
246
-                            thread_size, groove, square, rectangle, angle,
247
-                            taper)
248
-{
249
-   // Number of turns needed.
250
-   n_turns = floor (length/pitch);
251
-
252
-   intersection () {
253
-
254
-      // Start one below z = 0.  Gives an extra turn at each end.
255
-      for (i=[-1*n_starts : n_turns+1]) {
256
-         translate ([0, 0, i*pitch]) {
257
-            metric_thread_turn (diameter, pitch, internal, n_starts,
258
-                                thread_size, groove, square, rectangle, angle,
259
-                                taper, i*pitch);
260
-         }
261
-      }
262
-
263
-      // Cut to length.
264
-      translate ([0, 0, length/2]) {
265
-         cube ([diameter*3, diameter*3, length], center=true);
266
-      }
267
-   }
268
-}
269
-
270
-
271
-// ----------------------------------------------------------------------------
272
-module metric_thread_turn (diameter, pitch, internal, n_starts, thread_size,
273
-                           groove, square, rectangle, angle, taper, z)
274
-{
275
-   n_segments = segments (diameter);
276
-   fraction_circle = 1.0/n_segments;
277
-   for (i=[0 : n_segments-1]) {
278
-
279
-      // Keep polyhedron "facets" aligned -- circumferentially -- with base
280
-      // cylinder facets.  (Patch contributed by rambetter@protonmail.com.)
281
-      rotate ([0, 0, (i + 0.5)*360*fraction_circle + 90]) {
282
-         translate ([0, 0, i*n_starts*pitch*fraction_circle]) {
283
-            //current_diameter = diameter - taper*(z + i*n_starts*pitch*fraction_circle);
284
-            thread_polyhedron ((diameter - taper*(z + i*n_starts*pitch*fraction_circle))/2,
285
-                               pitch, internal, n_starts, thread_size, groove,
286
-                               square, rectangle, angle);
287
-         }
288
-      }
289
-   }
290
-}
291
-
292
-
293
-// ----------------------------------------------------------------------------
294
-module thread_polyhedron (radius, pitch, internal, n_starts, thread_size,
295
-                          groove, square, rectangle, angle)
296
-{
297
-   n_segments = segments (radius*2);
298
-   fraction_circle = 1.0/n_segments;
299
-
300
-   local_rectangle = rectangle ? rectangle : 1;
301
-
302
-   h = (square || rectangle) ? thread_size*local_rectangle/2 : thread_size / (2 * tan(angle));
303
-   outer_r = radius + (internal ? h/20 : 0); // Adds internal relief.
304
-   //echo (str ("outer_r: ", outer_r));
305
-
306
-   // A little extra on square thread -- make sure overlaps cylinder.
307
-   h_fac1 = (square || rectangle) ? 1.1 : 0.875;
308
-   inner_r = radius - h*h_fac1; // Does NOT do Dmin_truncation - do later with
309
-                                // cylinder.
310
-
311
-   translate_y = groove ? outer_r + inner_r : 0;
312
-   reflect_x   = groove ? 1 : 0;
313
-
314
-   // Make these just slightly bigger (keep in proportion) so polyhedra will
315
-   // overlap.
316
-   x_incr_outer = (! groove ? outer_r : inner_r) * fraction_circle * 2 * PI * 1.02;
317
-   x_incr_inner = (! groove ? inner_r : outer_r) * fraction_circle * 2 * PI * 1.02;
318
-   z_incr = n_starts * pitch * fraction_circle * 1.005;
319
-
320
-   /*
321
-    (angles x0 and x3 inner are actually 60 deg)
322
-
323
-                          /\  (x2_inner, z2_inner) [2]
324
-                         /  \
325
-   (x3_inner, z3_inner) /    \
326
-                  [3]   \     \
327
-                        |\     \ (x2_outer, z2_outer) [6]
328
-                        | \    /
329
-                        |  \  /|
330
-             z          |[7]\/ / (x1_outer, z1_outer) [5]
331
-             |          |   | /
332
-             |   x      |   |/
333
-             |  /       |   / (x0_outer, z0_outer) [4]
334
-             | /        |  /     (behind: (x1_inner, z1_inner) [1]
335
-             |/         | /
336
-    y________|          |/
337
-   (r)                  / (x0_inner, z0_inner) [0]
338
-
339
-   */
340
-
341
-   x1_outer = outer_r * fraction_circle * 2 * PI;
342
-
343
-   z0_outer = (outer_r - inner_r) * tan(angle);
344
-   //echo (str ("z0_outer: ", z0_outer));
345
-
346
-   //polygon ([[inner_r, 0], [outer_r, z0_outer],
347
-   //        [outer_r, 0.5*pitch], [inner_r, 0.5*pitch]]);
348
-   z1_outer = z0_outer + z_incr;
349
-
350
-   // Give internal square threads some clearance in the z direction, too.
351
-   bottom = internal ? 0.235 : 0.25;
352
-   top    = internal ? 0.765 : 0.75;
353
-
354
-   translate ([0, translate_y, 0]) {
355
-      mirror ([reflect_x, 0, 0]) {
356
-
357
-         if (square || rectangle) {
358
-
359
-            // Rule for face ordering: look at polyhedron from outside: points must
360
-            // be in clockwise order.
361
-            polyhedron (
362
-               points = [
363
-                         [-x_incr_inner/2, -inner_r, bottom*thread_size],         // [0]
364
-                         [x_incr_inner/2, -inner_r, bottom*thread_size + z_incr], // [1]
365
-                         [x_incr_inner/2, -inner_r, top*thread_size + z_incr],    // [2]
366
-                         [-x_incr_inner/2, -inner_r, top*thread_size],            // [3]
367
-
368
-                         [-x_incr_outer/2, -outer_r, bottom*thread_size],         // [4]
369
-                         [x_incr_outer/2, -outer_r, bottom*thread_size + z_incr], // [5]
370
-                         [x_incr_outer/2, -outer_r, top*thread_size + z_incr],    // [6]
371
-                         [-x_incr_outer/2, -outer_r, top*thread_size]             // [7]
372
-                        ],
373
-
374
-               faces = [
375
-                         [0, 3, 7, 4],  // This-side trapezoid
376
-
377
-                         [1, 5, 6, 2],  // Back-side trapezoid
378
-
379
-                         [0, 1, 2, 3],  // Inner rectangle
380
-
381
-                         [4, 7, 6, 5],  // Outer rectangle
382
-
383
-                         // These are not planar, so do with separate triangles.
384
-                         [7, 2, 6],     // Upper rectangle, bottom
385
-                         [7, 3, 2],     // Upper rectangle, top
386
-
387
-                         [0, 5, 1],     // Lower rectangle, bottom
388
-                         [0, 4, 5]      // Lower rectangle, top
389
-                        ]
390
-            );
391
-         } else {
392
-
393
-            // Rule for face ordering: look at polyhedron from outside: points must
394
-            // be in clockwise order.
395
-            polyhedron (
396
-               points = [
397
-                         [-x_incr_inner/2, -inner_r, 0],                        // [0]
398
-                         [x_incr_inner/2, -inner_r, z_incr],                    // [1]
399
-                         [x_incr_inner/2, -inner_r, thread_size + z_incr],      // [2]
400
-                         [-x_incr_inner/2, -inner_r, thread_size],              // [3]
401
-
402
-                         [-x_incr_outer/2, -outer_r, z0_outer],                 // [4]
403
-                         [x_incr_outer/2, -outer_r, z0_outer + z_incr],         // [5]
404
-                         [x_incr_outer/2, -outer_r, thread_size - z0_outer + z_incr], // [6]
405
-                         [-x_incr_outer/2, -outer_r, thread_size - z0_outer]    // [7]
406
-                        ],
407
-
408
-               faces = [
409
-                         [0, 3, 7, 4],  // This-side trapezoid
410
-
411
-                         [1, 5, 6, 2],  // Back-side trapezoid
412
-
413
-                         [0, 1, 2, 3],  // Inner rectangle
414
-
415
-                         [4, 7, 6, 5],  // Outer rectangle
416
-
417
-                         // These are not planar, so do with separate triangles.
418
-                         [7, 2, 6],     // Upper rectangle, bottom
419
-                         [7, 3, 2],     // Upper rectangle, top
420
-
421
-                         [0, 5, 1],     // Lower rectangle, bottom
422
-                         [0, 4, 5]      // Lower rectangle, top
423
-                        ]
424
-            );
425
-         }
426
-      }
427
-   }
428
-}
429
-
430
-
431
-

+ 152
- 72
hardware/trackball.scad View File

@@ -15,9 +15,6 @@
15 15
  * For the PMW3360 breakout board get this:
16 16
  * https://github.com/jfedor2/pmw3360-breakout
17 17
  *
18
- * The "Threads" library used by this project is:
19
- * Copyright 2022 Dan Kirshner - dan_kirshner@yahoo.com
20
- *
21 18
  * This program is free software: you can redistribute it and/or modify
22 19
  * it under the terms of the GNU General Public License as published by
23 20
  * the Free Software Foundation, either version 3 of the License, or
@@ -34,10 +31,6 @@
34 31
 // https://www.thingiverse.com/thing:421524
35 32
 use <external/cherry_mx.scad>
36 33
 
37
-// https://dkprojects.net/openscad-threads/
38
-use <external/threads.scad>
39
-//use <threadlib.scad>
40
-
41 34
 // ######################
42 35
 // ## Rendering Select ##
43 36
 // ######################
@@ -48,7 +41,9 @@ use <external/threads.scad>
48 41
 //mx_switch_cutout(wall);
49 42
 //mx_switch_test();
50 43
 //roller_mount_test();
44
+
51 45
 roller_mount_tri();
46
+
52 47
 //roller_holder();
53 48
 //trackball();
54 49
 
@@ -63,12 +58,11 @@ roller_ball_h = 8;
63 58
 roller_count = 3;
64 59
 
65 60
 wall = 3.0;
66
-
67
-cut_roller_holder = false;
68
-draw_threads = true;
69 61
 $c = 0.1;
70 62
 $e = 0.01;
71 63
 
64
+cut_roller_holder = false;
65
+
72 66
 // #######################
73 67
 // ## Raspberry Pi Pico ##
74 68
 // #######################
@@ -124,6 +118,16 @@ sensor_pin_pitch = 0.89;
124 118
 
125 119
 sensor_pin1_to_optical_center = 5.66;
126 120
 
121
+sensor_lens_cutout_r = 2.0;
122
+sensor_lens_cutout_w = 4.0;
123
+sensor_lens_cutout_growth = 0.25;
124
+sensor_lens_cutout_to_chip = 6.71 - 1.60;
125
+sensor_lens_baseplate_h = 2.40;
126
+
127
+sensor_lens_d = 19.0;
128
+sensor_lens_w = 21.35;
129
+sensor_lens_off = 10.97;
130
+
127 131
 // ######################
128 132
 // ## MX Switch Cutout ##
129 133
 // ######################
@@ -149,10 +153,12 @@ mx_travel = 3.9;
149 153
 // ### Implementation ###
150 154
 // ######################
151 155
 
152
-m3_thread=2.7;
153
-m2_thread=1.8;
156
+base_dia = pico_l + 9;
157
+
158
+m3_thread = 2.7;
159
+m2_thread = 1.8;
160
+
154 161
 roller_thread_dia = roller_dia + 5.0;
155
-roller_thread_pitch = 2.0;
156 162
 roller_h = roller_dia + 7.0;
157 163
 roller_ball_h_off = 0.4;
158 164
 roller_ball_hold_off = 0.5;
@@ -167,7 +173,7 @@ ball_h = 15; // todo
167 173
 
168 174
 switch_test_w = 25;
169 175
 
170
-$fn = 42;
176
+$fn = 100;
171 177
 
172 178
 function sphere_r_at_h(h, r) = r * sin(acos(h / r));
173 179
 function sphere_angle_at_rh(h, r) = acos(h / r);
@@ -230,6 +236,38 @@ module pico() {
230 236
     }
231 237
 }
232 238
 
239
+module sensor_lens_cutout_intern() {
240
+    cylinder(d = sensor_lens_cutout_r * 2, h = $e);
241
+    
242
+    translate([-sensor_lens_cutout_r, 0, 0])
243
+    cube([sensor_lens_cutout_r * 2, sensor_lens_cutout_w, $e]);
244
+}
245
+
246
+module rounded_cube(x, y, z, r) {
247
+    hull()
248
+    for (tx = [r, x - r])
249
+    for (ty = [r, y - r])
250
+    translate([tx, ty, 0])
251
+    cylinder(d = r * 2, h = z);
252
+}
253
+
254
+module sensor_lens_cutout() {
255
+    translate([0, 0, sensor_lens_cutout_to_chip])
256
+    hull() {
257
+        translate([0, 0, sensor_lens_baseplate_h - $e])
258
+        sensor_lens_cutout_intern();
259
+        
260
+        scale(1 + sensor_lens_cutout_growth * sensor_lens_baseplate_h)
261
+        sensor_lens_cutout_intern();
262
+    }
263
+    
264
+    translate([-sensor_lens_d / 2, -sensor_lens_w + sensor_lens_off, 0])
265
+    rounded_cube(sensor_lens_d, sensor_lens_w, sensor_lens_cutout_to_chip, 6);
266
+    
267
+    translate([-3 / 2, -sensor_lens_w + sensor_lens_off - 0.5, 0])
268
+    cube([3, 0.5, sensor_lens_cutout_to_chip]);
269
+}
270
+
233 271
 module sensor() {
234 272
     translate([-sensor_w / 2, -sensor_l / 2, 0])
235 273
     difference() {
@@ -258,13 +296,18 @@ module sensor() {
258 296
     translate([-sensor_pin_d / 2 + x, -sensor_pin_w / 2, -sensor_chip_h + sensor_pin_off_top])
259 297
     cube([sensor_pin_d, sensor_pin_w, sensor_pin_h]);
260 298
     
261
-    color("cyan")
262
-    translate([0, -sensor_l / 2 + sensor_cut_off_y + sensor_cut_h - sensor_cut_edge_to_pin1 - sensor_pin1_to_optical_center, -sensor_chip_h + 1])
263
-    cylinder(d = 0.2, h = sensor_ball_to_chip_bottom - 1);
299
+    translate([0, -sensor_l / 2 + sensor_cut_off_y + sensor_cut_h - sensor_cut_edge_to_pin1 - sensor_pin1_to_optical_center, 0]) {
300
+        color("cyan")
301
+        translate([0, 0, -sensor_chip_h + 1])
302
+        cylinder(d = 0.2, h = sensor_ball_to_chip_bottom - 1);
303
+        
304
+        %color("blue")
305
+        sensor_lens_cutout();
306
+    }
264 307
 }
265 308
 module ball_and_roller() {
266 309
     color("red")
267
-    sphere(d = ball_dia, $fn = 200);
310
+    sphere(d = ball_dia, $fn = $fn * 2);
268 311
     
269 312
     for (r = [0 : roller_count - 1])
270 313
     rotate([0, 0, roller_mount_angle_off + 360 / roller_count * r])
@@ -275,44 +318,43 @@ module ball_and_roller() {
275 318
 }
276 319
 
277 320
 module roller_holder() {
278
-
279
-    echo(roller_h);
280 321
     translate([0, 0, -roller_h + roller_dia / 2])
281 322
     difference() {
282 323
         color("magenta")
283 324
         union() {
284 325
             // top screw part
285 326
             translate([0, 0,  roller_h-roller_dia/2 + roller_ball_h_off-3])
286
-                cylinder(d1 = roller_mount_dia, d2=roller_dia+1,  h = 3);
287
-            cylinder(d = roller_mount_dia, h = roller_h-roller_dia/2 + roller_ball_h_off-3);
327
+            cylinder(d1 = roller_mount_dia, d2=roller_dia+1,  h = 3);
288 328
             
329
+            cylinder(d = roller_mount_dia, h = roller_h-roller_dia/2 + roller_ball_h_off-3);
289 330
         }
290 331
         
291
-        translate([0, 0, -$e]) {
292
-            cylinder(d = roller_thread_hole, h = $e+ roller_h - roller_dia / 2 + roller_ball_h_off + roller_ball_hold_off);
293
-        }
332
+        translate([0, 0, -$e])
333
+        cylinder(d = roller_thread_hole, h = $e+ roller_h - roller_dia / 2 + roller_ball_h_off + roller_ball_hold_off);
294 334
     
295 335
         translate([0, 0, roller_h - roller_dia / 2])
296
-            sphere(d = roller_dia , $fn=$fn*4 );
336
+        sphere(d = roller_dia, $fn = $fn * 2);
297 337
 
298
-        
299
-        if (cut_roller_holder) {
300
-            translate([-roller_thread_dia / 2 - 1, -roller_thread_dia, -1])
301
-                cube([roller_thread_dia + 2, roller_thread_dia, roller_h + 2]);
302
-        }
338
+        if (cut_roller_holder)
339
+        translate([-roller_thread_dia / 2 - 1, -roller_thread_dia, -1])
340
+        cube([roller_thread_dia + 2, roller_thread_dia, roller_h + 2]);
303 341
     }
304 342
     
305 343
     %color("blue")
306
-    sphere(d = roller_dia);
344
+    sphere(d = roller_dia, $fn = $fn * 2);
307 345
 }
308 346
 
309 347
 module roller_mount() {
310
-    echo(roller_h);
311 348
     translate([0, 0, -1-roller_h + roller_dia / 2]) {
312 349
         difference() {
313 350
             cylinder(d=roller_mount_dia+wall,h=roller_h/2);
314
-            translate([0,0,1])
351
+            
352
+            translate([0, 0, 1])
315 353
             cylinder(d=roller_mount_dia+$c*2,h=roller_h/2+$e);
354
+
355
+            if (cut_roller_holder)
356
+            translate([-roller_thread_dia / 2 - 1, -roller_thread_dia, -1])
357
+            cube([roller_thread_dia + 2, roller_thread_dia, roller_h + 2]);
316 358
         }
317 359
     }
318 360
 }
@@ -322,62 +364,103 @@ module roller_mount_test() {
322 364
     roller_mount();
323 365
 }
324 366
 
325
-module roller_mount_tri() {
367
+roller_mount_holder_gap = 0.8;
368
+sensor_pcb_mount_gap = 2.0;
326 369
 
327
-difference() {
328
-    union(){
329
-        difference() {
330
-             hull() {
331
-                translate([0, 0, 0])
370
+sensor_pcb_support_h = 1.6 + 3.4;
371
+
372
+module roller_mount_tri() {
373
+    %ball_and_roller();
374
+    
375
+    difference() {
376
+        union() {
377
+            difference() {
378
+                hull() {
379
+                    for (r = [0 : roller_count - 1])
380
+                    rotate([0, 0, roller_mount_angle_off + 360 / roller_count * r])
381
+                    translate([sphere_r_at_h(roller_ball_h - ball_dia / 2, ball_dia / 2), 0, -ball_dia / 2 + roller_ball_h])
382
+                    rotate([0, 180 + sphere_angle_at_rh(roller_ball_h - ball_dia / 2, ball_dia / 2), 0])
383
+                    translate([0, 0, -roller_h])
384
+                    cylinder(d = roller_mount_dia + wall + 1, h = roller_h - 3);
385
+                    
386
+                    translate([0, 0, -ball_dia / 2 - 11])
387
+                    cylinder(d = base_dia, h = $e);
388
+                }
389
+            
332 390
                 for (r = [0 : roller_count - 1])
333 391
                 rotate([0, 0, roller_mount_angle_off + 360 / roller_count * r])
334 392
                 translate([sphere_r_at_h(roller_ball_h - ball_dia / 2, ball_dia / 2), 0, -ball_dia / 2 + roller_ball_h])
335 393
                 rotate([0, 180 + sphere_angle_at_rh(roller_ball_h - ball_dia / 2, ball_dia / 2), 0])
336 394
                 translate([0, 0, -roller_h])
337
-                cylinder(d=roller_mount_dia+wall+1,h=roller_h+1);
395
+                cylinder(d = roller_mount_dia + roller_mount_holder_gap, h = ball_dia / 2 + roller_h);
338 396
                 
339
-                translate([0,0,-ball_dia/2-5])
340
-                cylinder(d=base_dia,h=$e);
397
+                sphere($fn = $fn * 2, d = ball_dia + $c * 2 + 4);
341 398
             }
342
-            
343
-            for (r = [0 : roller_count - 1])
344
-            rotate([0, 0, roller_mount_angle_off + 360 / roller_count * r])
345
-            translate([sphere_r_at_h(roller_ball_h - ball_dia / 2, ball_dia / 2), 0, -ball_dia / 2 + roller_ball_h])
346
-            rotate([0, 180 + sphere_angle_at_rh(roller_ball_h - ball_dia / 2, ball_dia / 2), 0])
347
-            translate([0, 0, -roller_h])
348
-            cylinder(d=roller_mount_dia+0.2,h=ball_dia/2+roller_h);
349
-            
350
-            sphere($fn=$fn*4, d=ball_dia+$c*2+1);
351
-            
352 399
         }
353
-        for (r = [0 : roller_count - 1])
354
-        rotate([0, 0, roller_mount_angle_off + 360 / roller_count * r])
355
-        translate([sphere_r_at_h(roller_ball_h - ball_dia / 2, ball_dia / 2), 0, -ball_dia / 2 + roller_ball_h])
356
-        rotate([0, 180 + sphere_angle_at_rh(roller_ball_h - ball_dia / 2, ball_dia / 2), 0])
357
-        translate([0, 0, 0])
358
-        roller_mount();
359
-    }
360 400
         
361
-        translate([0, 0, 0])
362 401
         for (r = [0 : roller_count - 1])
363 402
         rotate([0, 0, roller_mount_angle_off + 360 / roller_count * r])
364 403
         translate([sphere_r_at_h(roller_ball_h - ball_dia / 2, ball_dia / 2), 0, -ball_dia / 2 + roller_ball_h])
365 404
         rotate([0, 180 + sphere_angle_at_rh(roller_ball_h - ball_dia / 2, ball_dia / 2), 0])
366 405
         translate([0, 0, -roller_h/2])
367 406
         rotate([0,-90,0])
368
-        translate([0,0,2])
369
-        {
370
-        cylinder(d=m2_thread,h=ball_dia);
371
-            translate([0,0,roller_mount_dia/4+wall])
372
-        cylinder(d=m2_thread+1,h=ball_dia);
407
+        translate([-2, 0, 2]) {
408
+            cylinder(d = m2_thread, h = ball_dia);
409
+            
410
+            translate([0, 0, roller_mount_dia / 4 + wall])
411
+            cylinder(d = m2_thread + 1, h = ball_dia);
373 412
         }
374
-}
413
+        
414
+        translate([0, 0, -ball_dia / 2 - ball_h])
415
+        translate([0, sensor_l / 2 - sensor_cut_off_y - sensor_cut_h + sensor_cut_edge_to_pin1 + sensor_pin1_to_optical_center, ball_h + sensor_chip_h - sensor_ball_to_chip_bottom])
416
+        translate([0, -sensor_l / 2 + sensor_cut_off_y + sensor_cut_h - sensor_cut_edge_to_pin1 - sensor_pin1_to_optical_center, 0])
417
+        sensor_lens_cutout();
418
+        
419
+        translate([-1, -1, -ball_dia / 2 - ball_h])
420
+        translate([0, sensor_l / 2 - sensor_cut_off_y - sensor_cut_h + sensor_cut_edge_to_pin1 + sensor_pin1_to_optical_center, ball_h + sensor_chip_h - sensor_ball_to_chip_bottom])
421
+        translate([-sensor_w / 2, -sensor_l / 2, -10])
422
+        cube([sensor_w + 2, sensor_l + 2, sensor_pcb_h + 10 + sensor_pcb_mount_gap]);
423
+        
424
+        // TODO test cable cutout
425
+        translate([-6, 0, -30.1])
426
+        cube([12, 50, 2]);
427
+        
428
+        if (cut_roller_holder)
429
+        translate([0, -base_dia / 2 - 1, -40])
430
+        cube([base_dia / 2 + 1, base_dia + 2, 40]);
431
+    }
375 432
     
433
+    translate([-sensor_w / 2, -sensor_l / 2, sensor_pcb_h])
434
+    translate([0, 0, -ball_dia / 2 - ball_h])
435
+    translate([0, sensor_l / 2 - sensor_cut_off_y - sensor_cut_h + sensor_cut_edge_to_pin1 + sensor_pin1_to_optical_center, ball_h + sensor_chip_h - sensor_ball_to_chip_bottom])
436
+    for (x = [0, sensor_hole_dist_x])
437
+    for (y = [0, sensor_hole_dist_y])
438
+    translate([sensor_hole_off_x + x, sensor_hole_off_y + y, 0])
439
+    difference() {
440
+        union() {
441
+            color("magenta")
442
+            cylinder(d = sensor_hole_dia + 1.5, h = sensor_pcb_mount_gap);
376 443
             
444
+            color("black")
445
+            translate([0, 0, -sensor_pcb_support_h])
446
+            cylinder(d = sensor_hole_dia + 0.5, h = sensor_pcb_support_h);
447
+        }
448
+        
449
+        cylinder(d = sensor_hole_dia - 0.2, h = sensor_pcb_mount_gap + 1);
450
+    }
451
+    
452
+    color("black")
453
+    for (x = [-5, 0, 5])
454
+    for (y = [-8, 0, 6.5])
455
+    if (((x == 0) && (y != 0)) || ((x != 0) && (y == 0)))
456
+    translate([x, y + 2, -30])
457
+    cylinder(d = sensor_hole_dia + 0.5, h = 8.5);
458
+        
459
+    %translate([0, 0, -ball_dia / 2 - ball_h])
460
+    translate([0, sensor_l / 2 - sensor_cut_off_y - sensor_cut_h + sensor_cut_edge_to_pin1 + sensor_pin1_to_optical_center, ball_h + sensor_chip_h - sensor_ball_to_chip_bottom])
461
+    sensor();
377 462
 }
378 463
 
379
-base_dia = pico_l + 9;
380
-
381 464
 module trackball() {
382 465
     %translate([0, 0, ball_dia / 2 + ball_h])
383 466
     ball_and_roller();
@@ -394,12 +477,9 @@ module trackball() {
394 477
     translate([sphere_r_at_h(roller_ball_h - ball_dia / 2, ball_dia / 2), 0, -ball_dia / 2 + roller_ball_h])
395 478
     rotate([0, 180 + sphere_angle_at_rh(roller_ball_h - ball_dia / 2, ball_dia / 2), 0])
396 479
     translate([0, 0, -roller_dia / 2])
397
-    translate([0, 0, -roller_h + roller_dia / 2 - roller_ball_h_off])
398 480
     roller_mount();
399 481
     
400 482
     color("grey")
401 483
     translate([0, 0, -8])
402 484
     cylinder(d = base_dia, h = wall);
403 485
 }
404
-
405
-

Loading…
Cancel
Save