Moved from Notes
103
desktop_arcade_machine/README.md
Normal file
@@ -0,0 +1,103 @@
|
||||
Desktop Arcade Machine
|
||||
==========================
|
||||
## Components
|
||||
| Qty | Component | Infos |
|
||||
| --- | --------- | ----- |
|
||||
| 1 | Raspberry Pi 3 Model B | |
|
||||
| 1 | Raspberry Pi 3 Power Supply - 5.1v 2.5A | I bought the official Raspberry Pi 3 power supply. Tested some of the third party power supply, and even using high quality cables, it wiould still result in under voltage. |
|
||||
| 1 | 8" 1024x768 IPS HE080IA-01D LCD Display | https://www.aliexpress.com/item/HDMI-VGA-AV-Control-Driver-Board-8-inch-HE080IA-01D-1024-768-IPS-high-definition-LCD/32325920866.html?spm=2114.13010608.0.0.SzvaUj |
|
||||
| 1 | Arcade Joystick + Buttons Kit | https://www.aliexpress.com/item/DIY-arcade-joystick-handle-set-kits-5-pin-24mm-30mm-push-buttons-spare-parts-USB-cable/32770679289.html?spm=2114.13010308.0.0.nqSdOB |
|
||||
| 2 | 40mm 4ohm 3W speaker | https://www.aliexpress.com/item/2pcs-Packs-4Ohm-3W-Full-range-Audio-Stereo-Speaker-40mm-Loudspeakers-Woofer-Speaker/32782192396.html?spm=2114.13010608.0.0.nlJkfT |
|
||||
| 1 | PAM8403 5V digital amplifier board | https://www.aliexpress.com/item/PAM8403-5V-Power-Audio-Amplifier-Board-2-Channel-3W-W-Volume-Control-Free-Shipping/32452488898.html?spm=2114.13010608.0.0.nlJkfT |
|
||||
| 1 | Short 20cm HDMI Male to Male cable | https://www.aliexpress.com/item/High-Speed-HDMI-Cable-Full-HD-Short-HDMI-Male-to-Male-Plug-Flat-Cable-Cord-Widely/32772823742.html?spm=2114.13010608.0.0.SzvaUj |
|
||||
| 1 | Short 30cm USB 2.0 male to female extension cable | https://www.aliexpress.com/item/30CM-USB-2-0-A-Male-to-USB2-0-A-Female-Extension-Molded-Panel-Mount-Extention/32573641881.html?spm=2114.13010608.0.0.nlJkfT |
|
||||
| 1 | Heat Sinks for Raspberry Pi 3 | https://www.aliexpress.com/item/Free-shipping-5pcs-lot-heat-sink-for-A4988-A4983-Stepper-Driver/1833231480.html?spm=2114.13010608.0.0.SzvaUj |
|
||||
| 6 | White LEDs | |
|
||||
| 6 | 100ohm resistors | |
|
||||
| 1 | 128GB SD Card | You can use a smaller card, but a bigger card allows you to dump in a lot more games. |
|
||||
| 1 | A4 Sized 0.5mm Thick Clear PVC Sheet | This is used for the marquee - cut to size: 210mm x 45mm |
|
||||
## Instructions
|
||||
|
||||
> ### Excerpt
|
||||
> 3D print all the pieces. I used PLA for stiffness. All my 3D models were designed to be printed without the need for any support structures. You will need a 3D printer with a minimum print volume of 220mm x 220mm x 120mm in order to print these files.
|
||||
|
||||
---
|
||||
1. Step 1
|
||||
|
||||
3D print all the pieces. I used PLA for stiffness. All my 3D models were designed to be printed without the need for any support structures. You will need a 3D printer with a minimum print volume of 220mm x 220mm x 120mm in order to print these files.
|
||||
|
||||
I should note that I actually designed and printed these parts \*before\* receiving the actual parts like the LCD screen, controller, speaker, amplifier etc. 3D printing takes quite a lot of time and I didn't want to wait till everything I ordered has arrived in the mail before I started printing. So, some of the parts were designed with some flexibility in terms of how it would be laid out. Also, this was a learning process for me as I am still relatively new to 3D printing, so some parts have gone through many changes as I experimented with the design. I believe all the files I uploaded should be correct, but in case there are any mistakes, do let me know.
|
||||
|
||||
**Please understand that I am sharing these files AS IS. You do need to have a decent knowledge of 3D printing, Raspberry Pi, soldering, etc. in order to put it all together.** Any information that I did not include here, you will be able to Google it.
|
||||
|
||||
Here are reference photos to give you a better idea of how all the pieces fit together.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
### Exploded views.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
### Completely assembled views.
|
||||
|
||||

|
||||

|
||||
|
||||
Most of the main pieces are held together using nuts and bolts, or screws. You will need M3 bolts of various lengths (probably 10mm - 16mm) and some screws. I am afraid I lost the specs of the screw I used, but it's about 10mm long and 2.5mm diameter. These were use for the marquee pieces.
|
||||
|
||||
I sprayed primer putty and sanded it down to a smooth finish before spraying matte black paint for the final finish. You want to make sure you sand the top edges of "Body - Front Left" and "Body - Front Right" so that they are nice and smooth, cause otherwise, when you rest your hands on them, the sharp edges will get irritating quite quickly.
|
||||
|
||||
In order to make it look like a commercial quality product, I did a lot of research into the designs of the artwork for old arcade machines. I took inspiration from them to create my own artwork for my arcade machine and had it commercially printed on vinyl stickers.
|
||||
|
||||
**Connecting Everything Together**
|
||||
|
||||
- The controller's USB connector will plug into the Raspberry Pi's USB socket.
|
||||
- The power connecter for the display will plug into the Raspberry Pi's USB socket.
|
||||
- The HDMI out on the Raspberry Pi needs to be connected to the HDMI input on the display controller board.
|
||||
- The speaker needs to be soldered to the amplifier circuit, and the amplfier circuit's power input needs to the connected to the Raspberry Pi's GPIO pin 4 & 6 for the 5V power supply. You also need to solder an earphone jack connector to the amplifier circuit and plug that into the Raspberry Pi's audio socket.
|
||||
- Solder together the LEDs and wire it to a USB connector. Plug it into the Raspberry Pi's USB socket.
|
||||
|
||||
So, everything is powered directly from the Raspberry Pi. The only cable going into the arcade machine is the Raspberry Pi's power supply cable.
|
||||
|
||||
**Software Setup**
|
||||
|
||||
You will need to get RetroPie setup and configured. For that, please check out RetroPie's website ([https://retropie.org.uk](https://retropie.org.uk)) and Google for anything you need. All the resources you need are out there!
|
||||
|
||||
2. Step 2
|
||||
|
||||
**Display Issue Fix**
|
||||
|
||||
The first time you try to power up the full setup, make sure to power the display from a SEPARATE USB power supply FIRST, before turning on your RPi. The display needs to be active first, otherwise your RPi would not use HDMI for display. Also, connect a keyboard to your RPi.
|
||||
|
||||
After powering up your Raspberry Pi, let it boot up all the way until Emulation Station/Attract Mode comes up (depending on your setup). **Exit** to terminal.
|
||||
|
||||
Open the Raspberry Pi configuration file for editing with this command:
|
||||
|
||||
**sudo nano /boot/config.txt**
|
||||
|
||||
Use arrows to get to the end of the file and add these 3 lines:
|
||||
|
||||
**#Always force HDMI output and enable HDMI sound**
|
||||
|
||||
**hdmi\_force\_hotplug=1**
|
||||
|
||||
**hdmi\_drive=2**
|
||||
|
||||
Save the changes by **pressing CTRL + O** and **ENTER**
|
||||
|
||||
Exit the editor by pressing **CTRL + X**
|
||||
|
||||
Now you can turn everything off, reconnect your display's power supply to RPi's USB socket. Now when you turn it on, your RPi will default to HDMI output even though the screen is powering up later than your RPi.
|
||||
BIN
desktop_arcade_machine/images/1332461491286001545.png
Normal file
|
After Width: | Height: | Size: 707 KiB |
BIN
desktop_arcade_machine/images/1959781491286273888.png
Normal file
|
After Width: | Height: | Size: 233 KiB |
BIN
desktop_arcade_machine/images/2138881491286174513.png
Normal file
|
After Width: | Height: | Size: 273 KiB |
BIN
desktop_arcade_machine/images/2145881491286092738.png
Normal file
|
After Width: | Height: | Size: 462 KiB |
BIN
desktop_arcade_machine/images/2822801491286021738.png
Normal file
|
After Width: | Height: | Size: 818 KiB |
BIN
desktop_arcade_machine/images/3681801491286072749.png
Normal file
|
After Width: | Height: | Size: 613 KiB |
BIN
desktop_arcade_machine/images/3716051491285922699.png
Normal file
|
After Width: | Height: | Size: 882 KiB |
BIN
desktop_arcade_machine/images/407391491286222781.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
desktop_arcade_machine/images/4476891491286370618.png
Normal file
|
After Width: | Height: | Size: 407 KiB |
BIN
desktop_arcade_machine/images/4767131491286149765.png
Normal file
|
After Width: | Height: | Size: 238 KiB |
BIN
desktop_arcade_machine/images/4779831491286197187.png
Normal file
|
After Width: | Height: | Size: 251 KiB |
BIN
desktop_arcade_machine/images/4833821491286389026.png
Normal file
|
After Width: | Height: | Size: 306 KiB |
BIN
desktop_arcade_machine/images/4949511491285896855.png
Normal file
|
After Width: | Height: | Size: 514 KiB |
BIN
desktop_arcade_machine/images/7632211491286039479.png
Normal file
|
After Width: | Height: | Size: 840 KiB |
BIN
desktop_arcade_machine/images/8436331491285957957.png
Normal file
|
After Width: | Height: | Size: 778 KiB |
BIN
desktop_arcade_machine/images/8491071491295148170.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
desktop_arcade_machine/images/8866051491285875547.png
Normal file
|
After Width: | Height: | Size: 463 KiB |
313
parametric_design_in_OpenSCAD.md
Normal file
@@ -0,0 +1,313 @@
|
||||
Parametric design in OpenSCAD
|
||||
==========================
|
||||
In the [previous article](https://blog.prusa3d.com/practical-problem-programming-objects-3d-printing-openscad_8415/), I’ve shown you how to create a spare part for an office chair using OpenSCAD. And I have also encouraged the readers to try and modify the values in the code to see how they affect the model’s shape. One of OpenSCAD’s biggest strengths is the ability to **easily incorporate parametric design.** It’s a feature that allows you to quickly and easily **change the design of a whole object just by modifying a few variables.** Today, I’m going to show you how to take advantage of this, and we will create\*\* another useful thing – an S-bracket.\*\*
|
||||
|
||||
**An S-shaped bracket** is something I print quite often because I like to put all sorts of devices on the underside of tables, racks and so on. Network switches, routers, USB hubs, card readers… thanks to the S-brackets, these things can be mounted on the underside of a desk, so they are always at hand, but they don’t get in the way.
|
||||
|
||||
[](https://blog.prusa3d.com/wp-content/uploads/2018/09/01_prehled.png)
|
||||
|
||||
In this picture, you can see a device mounted on the underside of a table using **red colored brackets.** They are exactly what we’re going to create today. Their shape and dimensions will be different for each device. For smaller and lighter devices, we require only a small and light bracket. Bigger things will require a more robust shape and probably also holes for screws, that will hold the brackets in place. We will need all shapes and sizes.
|
||||
|
||||
This is a typical task for OpenSCAD’s parametric design. So let’s take a look how to create a single model and modify it by changing a few variables.
|
||||
|
||||
**Please note that throughout the article, I’m explaining various pieces of code separately to save space. If you want to see the complete code, either scroll to the last two chapters or download the sample code from the last paragraph.**
|
||||
|
||||
### Round cube
|
||||
|
||||
One of the most used constructs when designing models is **a cube with rounded corners.** Typically, this is generated in OpenSCAD using a *‘hull’* function. This function will create an object that tightly encompasses all of its child objects.
|
||||
|
||||
[](https://blog.prusa3d.com/wp-content/uploads/2018/09/02_hull.png)
|
||||
|
||||
These four cylinders will be the base for our cuboid. When we apply the *‘hull’* function, we will get the required shape.
|
||||
|
||||
[](https://blog.prusa3d.com/wp-content/uploads/2018/09/03_hull.png)
|
||||
|
||||
However, if we wanted to have **rounded corners** not only in the projection view but **on all edges,** then we would have to use eight spheres instead of four cylinders (two spheres in each corner). But in this case, cylinders will be perfectly fine. And since we will be using this shape regularly, we will write a **module** (this is OpenSCAD’s term for something that’s usually called a **method** in other programming languages), which will create a cuboid with dimensions and edge curvature based on variables we enter.
|
||||
|
||||
The module will be called *‘rcube’* and its code is below. However, at this point, it won’t do anything when you copy-paste it into OpenSCAD, we need to add a bit more.
|
||||
|
||||
```
|
||||
module rcube(size, radius) {
|
||||
hull() {
|
||||
translate([radius, radius]) cylinder(r = radius, h = size[2]);
|
||||
translate([size[0] - radius, radius]) cylinder(r = radius, h = size[2]);
|
||||
translate([size[0] - radius, size[1] - radius]) cylinder(r = radius, h = size[2]);
|
||||
translate([radius, size[1] - radius]) cylinder(r = radius, h = size[2]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This module works the same way as the *‘cube’* command, however, it takes into account one more parameter – curvature of rounded edges.
|
||||
|
||||
Sometimes, when we create more complex objects, we need to have different curvature of rounded edges in each corner. That’s easy – the *‘radius’* parameter will be a vector containing four different curvature values, as follows:
|
||||
|
||||
```
|
||||
module rcube(size, radius) {
|
||||
hull() {
|
||||
translate([radius[0], radius[0]]) cylinder(r = radius[0], h = size[2]);
|
||||
translate([size[0] - radius[1], radius[1]]) cylinder(r = radius[1], h = size[2]);
|
||||
translate([size[0] - radius[2], size[1] - radius[2]]) cylinder(r = radius[2], h = size[2]);
|
||||
translate([radius[3], size[1] - radius[3]]) cylinder(r = radius[3], h = size[2]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can create the following shape by calling *‘rcube([100,50,10], [5,10,20]);’* (without quotes) at the end of the code above:
|
||||
|
||||
[](https://blog.prusa3d.com/wp-content/uploads/2018/09/04_rcube.png)
|
||||
|
||||
Our module is quite good now, but in the current stage, it won’t be able to take into account the fact that some corners have to be sharp. If you enter ‘0’ as the curvature value, the respective corner will be ignored. Let’s modify the code, so when you enter ‘0’, it will create a cube [1,1,n] instead of a cylinder.
|
||||
|
||||
```
|
||||
module rcube(size, radius) {
|
||||
hull() {
|
||||
// BL
|
||||
if(radius[0] == 0) cube([1, 1, size[2]]);
|
||||
else translate([radius[0], radius[0]]) cylinder(r = radius[0], h = size[2]);
|
||||
// BR
|
||||
if(radius[1] == 0) translate([size[0] - 1, 0]) cube([1, 1, size[2]]);
|
||||
else translate([size[0] - radius[1], radius[1]]) cylinder(r = radius[1], h = size[2]);
|
||||
// TR
|
||||
if(radius[2] == 0) translate([size[0] - 1, size[1] - 1])cube([1, 1, size[2]]);
|
||||
else translate([size[0] - radius[2], size[1] - radius[2]]) cylinder(r = radius[2], h = size[2]);
|
||||
// TL
|
||||
if(radius[3] == 0) translate([0, size[1] - 1]) cube([1, 1, size[2]]);
|
||||
else translate([radius[3], size[1] - radius[3]]) cylinder(r = radius[3], h = size[2]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The *‘rcube([100, 50, 10], [15, 0, 15, 0]);’* code will now generate a cuboid with two sharp corners and two rounded corners:
|
||||
|
||||
[](https://blog.prusa3d.com/wp-content/uploads/2018/09/05_rcube.png)
|
||||
|
||||
Alright, now let’s focus on making the code more user-friendly, mainly because the users will be, in fact, usually us. It would be great if the *‘radius’* parameter was universal.
|
||||
|
||||
- If it is **a** **simple variable** (a scalar), it determines the radius of a curvature, which is the same for all corners
|
||||
- If it is **a** **two-component vector,** the first number is the curvature of the front corners, the second number is the curvature of the back corners
|
||||
- If it is **a** **four-component vector,** the numbers determine the curvature of all corners, starting with the front left corner and continuing with other corners counter-clockwise
|
||||
|
||||
We can find out the length of a vector by using the *‘len()’* function. If a scalar is detected, the returned value will be ***undef*,** otherwise, the length of the vector will be returned. We can utilize this, so when the length is not 4, the module will call itself with corresponding parameters.
|
||||
|
||||
```
|
||||
module rcube(size, radius) {
|
||||
if(len(radius) == undef) {
|
||||
// The same radius on all corners
|
||||
rcube(size, [radius, radius, radius, radius]);
|
||||
} else if(len(radius) == 2) {
|
||||
// Different radii on top and bottom
|
||||
rcube(size, [radius[0], radius[0], radius[1], radius[1]]);
|
||||
} else if(len(radius) == 4) {
|
||||
// Different radius on different corners
|
||||
hull() {
|
||||
// BL
|
||||
if(radius[0] == 0) cube([1, 1, size[2]]);
|
||||
else translate([radius[0], radius[0]]) cylinder(r = radius[0], h = size[2]);
|
||||
// BR
|
||||
if(radius[1] == 0) translate([size[0] - 1, 0]) cube([1, 1, size[2]]);
|
||||
else translate([size[0] - radius[1], radius[1]]) cylinder(r = radius[1], h = size[2]);
|
||||
// TR
|
||||
if(radius[2] == 0) translate([size[0] - 1, size[1] - 1])cube([1, 1, size[2]]);
|
||||
else translate([size[0] - radius[2], size[1] - radius[2]]) cylinder(r = radius[2], h = size[2]);
|
||||
// TL
|
||||
if(radius[3] == 0) translate([0, size[1] - 1]) cube([1, 1, size[2]]);
|
||||
else translate([radius[3], size[1] - radius[3]]) cylinder(r = radius[3], h = size[2]);
|
||||
}
|
||||
} else {
|
||||
echo("ERROR: Incorrect length of 'radius' parameter. Expecting integer or vector with length 2 or 4.");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Creating an S-bracket
|
||||
|
||||
Why do we care about rounded cubes so much? Well, when you look at the S-bracket closer, you will realize that it actually consists of three cubes (two of them with rounded corners) – it’s nicely visible in the picture below:
|
||||
|
||||
[](https://blog.prusa3d.com/wp-content/uploads/2018/09/06_bracket_schema.png)
|
||||
|
||||
So, using the latest version of the *‘rcube’* module from the previous chapter, we can create a parametric design using this code (which needs to be placed at the start of the code from the last chapter):
|
||||
|
||||
```
|
||||
width = 30;
|
||||
height = 30;
|
||||
top_length = 30;
|
||||
bottom_length = 20;
|
||||
number_of_holes = 2;
|
||||
wall_thickness = 3;
|
||||
hole_diameter = 4;
|
||||
|
||||
$fn = 16;
|
||||
|
||||
rcube([bottom_length + wall_thickness, wall_thickness, width], [wall_thickness / 2, wall_thickness / 2, 0, wall_thickness / 2]);
|
||||
translate([bottom_length, wall_thickness]) cube([wall_thickness, height, width]);
|
||||
translate([bottom_length, height]) rcube([top_length + wall_thickness, wall_thickness, width], [0, wall_thickness / 2, 0, 0]);
|
||||
```
|
||||
|
||||
Merging both pieces of code will give you the following result:
|
||||
|
||||
[](https://blog.prusa3d.com/wp-content/uploads/2018/09/07_bracket_bez_der.png)
|
||||
|
||||
The bracket looks good and we could actually leave it in this shape – if we wanted to glue it to the underside of the table – which is often perfectly suitable solution. However, if we want to attach it using screws, we need to make some holes first.
|
||||
|
||||
But how many? For smaller brackets, one screw can be enough. Two is better, though, so the bracket doesn’t rotate around the screw. On the other hand, heavier objects will need a sturdier bracket with more holes for at least three to six screws. This means that our bracket needs to have a variable number of holes, let’s say from zero to six, as seen in the picture below.
|
||||
|
||||
[](https://blog.prusa3d.com/wp-content/uploads/2018/09/08_diry.png)
|
||||
|
||||
Basically, it’s the same problem we solved with the *‘rcube’* module when we had to decide, based on the number of vector components, what will be determined by the values. The code for S-bracket generator *(without the ‘rcube’ module code)* looks like this:
|
||||
|
||||
```
|
||||
width = 30;
|
||||
height = 30;
|
||||
top_length = 30;
|
||||
bottom_length = 20;
|
||||
number_of_holes = 2;
|
||||
wall_thickness = 10;
|
||||
hole_diameter = 4;
|
||||
|
||||
fudge = 1;
|
||||
$fn = 16;
|
||||
|
||||
rcube([bottom_length + wall_thickness, wall_thickness, width], [wall_thickness / 2, wall_thickness / 2, 0, wall_thickness / 2]);
|
||||
translate([bottom_length, wall_thickness]) cube([wall_thickness, height, width]);
|
||||
translate([bottom_length, height]) difference() {
|
||||
rcube([top_length + wall_thickness, wall_thickness, width], [0, wall_thickness / 2, 0, 0]);
|
||||
if(number_of_holes == 0) {
|
||||
// Do nothing, already done
|
||||
} else if(number_of_holes == 1) {
|
||||
// Single centered hole
|
||||
translate([wall_thickness + top_length * .50, -fudge, width * .50]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
} else if(number_of_holes == 2) {
|
||||
// Two diagonal holes
|
||||
translate([wall_thickness + top_length * .30, -fudge, width * .30]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .70, -fudge, width * .70]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
} else if(number_of_holes == 3) {
|
||||
// Three holes in traingle
|
||||
translate([wall_thickness + top_length * .30, -fudge, width * .30]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .30, -fudge, width * .70]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .70, -fudge, width * .50]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
} else if(number_of_holes == 4) {
|
||||
// Four holes in corners
|
||||
translate([wall_thickness + top_length * .30, -fudge, width * .30]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .70, -fudge, width * .70]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .30, -fudge, width * .70]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .70, -fudge, width * .30]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
} else if(number_of_holes == 5) {
|
||||
// Four holes in corners and one in cender
|
||||
translate([wall_thickness + top_length * .25, -fudge, width * .25]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .75, -fudge, width * .75]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .25, -fudge, width * .75]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .75, -fudge, width * .25]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .50, -fudge, width * .50]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
} else if(number_of_holes == 6) {
|
||||
// Six holes
|
||||
translate([wall_thickness + top_length * .25, -fudge, width * .25]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .50, -fudge, width * .25]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .75, -fudge, width * .25]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .25, -fudge, width * .75]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .50, -fudge, width * .75]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .75, -fudge, width * .75]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
} else {
|
||||
echo("ERROR: Unsupported number of holes (supported 0-6");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And that’s pretty much it. Just add the *‘rcube’* module code and try the preview in OpenSCAD. However, I want to show you how to easily modify the code even further.
|
||||
|
||||
### Further modifications
|
||||
|
||||
In the previous chapter, we have finished our work on the S-bracket generator, which will be good enough for daily use. But we can tweak it a bit more. Personally, I recommend moving the bracket generator into a separate module, so we can call it with additional parameters. Let’s say we want to generate multiple brackets at the same time, however, we want each to have a different number of holes. Once we have the generator in a separate module called ‘bracket’ (see the code below), we can create the bracket at the position we set with the ‘translate’ command and give it a required number of holes. This is just an example of how to modify the code further, you will most likely be fine with the code from the previous chapter.
|
||||
|
||||
[](https://blog.prusa3d.com/wp-content/uploads/2018/09/openscad_v2.jpg)
|
||||
|
||||
```
|
||||
fudge = 1;
|
||||
$fn = 16;
|
||||
|
||||
translate([000, 0]) bracket(30, 30, 30, 30, number_of_holes = 1);
|
||||
translate([080, 0]) bracket(30, 30, 30, 30, number_of_holes = 2);
|
||||
translate([160, 0]) bracket(30, 30, 30, 30, number_of_holes = 3);
|
||||
translate([240, 0]) bracket(30, 30, 30, 30, number_of_holes = 4);
|
||||
translate([320, 0]) bracket(30, 30, 30, 30, number_of_holes = 5);
|
||||
translate([400, 0]) bracket(30, 30, 30, 30, number_of_holes = 6);
|
||||
|
||||
module bracket(width, height, top_length, bottom_length, number_of_holes = 2, wall_thickness = 3, hole_diameter = 4) {
|
||||
rcube([bottom_length + wall_thickness, wall_thickness, width], [wall_thickness / 2, wall_thickness / 2, 0, wall_thickness / 2]);
|
||||
translate([bottom_length, wall_thickness]) cube([wall_thickness, height, width]);
|
||||
translate([bottom_length, height]) difference() {
|
||||
rcube([top_length + wall_thickness, wall_thickness, width], [0, wall_thickness / 2, 0, 0]);
|
||||
if(number_of_holes == 0) {
|
||||
// Do nothing, already done
|
||||
} else if(number_of_holes == 1) {
|
||||
// Single centered hole
|
||||
translate([wall_thickness + top_length * .50, -fudge, width * .50]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
} else if(number_of_holes == 2) {
|
||||
// Two diagonal holes
|
||||
translate([wall_thickness + top_length * .30, -fudge, width * .30]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .70, -fudge, width * .70]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
} else if(number_of_holes == 3) {
|
||||
// Three holes in traingle
|
||||
translate([wall_thickness + top_length * .30, -fudge, width * .30]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .30, -fudge, width * .70]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .70, -fudge, width * .50]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
} else if(number_of_holes == 4) {
|
||||
// Four holes in corners
|
||||
translate([wall_thickness + top_length * .30, -fudge, width * .30]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .70, -fudge, width * .70]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .30, -fudge, width * .70]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .70, -fudge, width * .30]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
} else if(number_of_holes == 5) {
|
||||
// Four holes in corners and one in cender
|
||||
translate([wall_thickness + top_length * .25, -fudge, width * .25]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .75, -fudge, width * .75]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .25, -fudge, width * .75]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .75, -fudge, width * .25]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .50, -fudge, width * .50]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
} else if(number_of_holes == 6) {
|
||||
// Six holes
|
||||
translate([wall_thickness + top_length * .25, -fudge, width * .25]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .50, -fudge, width * .25]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .75, -fudge, width * .25]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .25, -fudge, width * .75]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .50, -fudge, width * .75]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
translate([wall_thickness + top_length * .75, -fudge, width * .75]) rotate([-90, 0, 0]) cylinder(d = hole_diameter, h = wall_thickness + 2 * fudge);
|
||||
} else {
|
||||
echo("ERROR: Unsupported number of holes (supported 0-6");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module rcube(size, radius) {
|
||||
if(len(radius) == undef) {
|
||||
// The same radius on all corners
|
||||
rcube(size, [radius, radius, radius, radius]);
|
||||
} else if(len(radius) == 2) {
|
||||
// Different radii on top and bottom
|
||||
rcube(size, [radius[0], radius[0], radius[1], radius[1]]);
|
||||
} else if(len(radius) == 4) {
|
||||
// Different radius on different corners
|
||||
hull() {
|
||||
// BL
|
||||
if(radius[0] == 0) cube([1, 1, size[2]]);
|
||||
else translate([radius[0], radius[0]]) cylinder(r = radius[0], h = size[2]);
|
||||
// BR
|
||||
if(radius[1] == 0) translate([size[0] - 1, 0]) cube([1, 1, size[2]]);
|
||||
else translate([size[0] - radius[1], radius[1]]) cylinder(r = radius[1], h = size[2]);
|
||||
// TR
|
||||
if(radius[2] == 0) translate([size[0] - 1, size[1] - 1])cube([1, 1, size[2]]);
|
||||
else translate([size[0] - radius[2], size[1] - radius[2]]) cylinder(r = radius[2], h = size[2]);
|
||||
// TL
|
||||
if(radius[3] == 0) translate([0, size[1] - 1]) cube([1, 1, size[2]]);
|
||||
else translate([radius[3], size[1] - radius[3]]) cylinder(r = radius[3], h = size[2]);
|
||||
}
|
||||
} else {
|
||||
echo("ERROR: Incorrect length of 'radius' parameter. Expecting integer or vector with length 2 or 4.");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Final thoughts and download links
|
||||
|
||||
This time, we took OpenSCAD programming to the next level, compared to the previous article. As demonstrated, one of OpenSCAD’s biggest strengths is the ability to easily generated object based on a few variables. Hopefully, you will find this piece of code useful and maybe you will modify it even further.
|
||||
|
||||
And for your convenience, the ready-to-compile codes are [available for download here](https://www.prusa3d.com/downloads/others/bracket_generator.zip).
|
||||
16
tir_sportif/patch_dispenser/patch_dispenser.scad
Normal file
@@ -0,0 +1,16 @@
|
||||
$fn=60;
|
||||
|
||||
include <BOSL2/std.scad>
|
||||
|
||||
union() {
|
||||
zcyl(d=75, l=3);
|
||||
cuboid([37.5,37.5,3], rounding=5, edges=[FRONT+LEFT], anchor=BACK+RIGHT);
|
||||
}
|
||||
zcyl(d=20, l=25, anchor=BOT);
|
||||
difference() {
|
||||
union() {
|
||||
tube(od=75, wall=3, l=25, anchor=BOT);
|
||||
rect_tube(size=37.5, h=25, wall=3, rounding=5, edges=[FRONT+LEFT], anchor=BOT+RIGHT+BACK);
|
||||
}
|
||||
cuboid([34.5,34.5,25], rounding=3, edges=[FRONT+LEFT], anchor=BOT+RIGHT+BACK);
|
||||
}
|
||||