Micro Quadcopter in OpenSCAD
by masterdezign in Workshop > 3D Printing
4948 Views, 36 Favorites, 0 Comments
Micro Quadcopter in OpenSCAD
3D printing (known in the industry as additive manufacturing) is a process of
fabrication of a 3D object from a digital model. 3D printer prices have significantly dropped during past decade, so 3D printing is much more common nowadays. In this tutorial we will create a micro quadcopter frame to be 3D printed yourself.
Supplies
CAD design and fabrication:
- OpenSCAD
- Access to an FDM printer
Micro copter (optional):
- 3D printed frame
- F-1607 DC motors with propellers (4x)
- Flight controller + remote control
- 150 mAh LiPo battery
Basic OpenSCAD: Motor Compartment Design
For starters, let's create emplacements for F-1607 DC motors. This part can be imagined as a shell around the motor, or a Boolean difference between the external box (gray cylinder) and the motor itself (red cylinder).
The motor dimensions given by Olimex are 7 mm diameter and 16.5 mm height. I have chosen shell size parameter to be 0.8 mm. I have lifted the inner cylinder by 0.8 mm (`translate`) so that the result is a box, not a tube. The red transparent cylinder only illustrates where the motor goes, so it will be not visible in the final rendering.
shell=0.8; difference() { cylinder(d=7 + 2 * shell, h=16.5); translate([0, 0, shell]) cylinder(d=7, h=16.5); }
How about the motor wires? We can carve out a side and a bottom holes using Boolean `difference` and `union` transformations.
module SlotF1607(h=16.5, d=7, shell=0.8, // Shell thickness slack=0.1 // Some extra space to accommodate a motor ) { difference() { // Motor compartment cylinder(d=d + 2 * shell, h=16.5); union () { // Motor emplacement translate([0, 0, shell]) cylinder(d=d + slack, h=16.5); // Bottom hole for motor contacts/wires cylinder(d=6, h=h, center=true); // Wires hole translate([d/4, 0, 0]) cube([d, 2.5, h * 3], center=true); } } }
Last but not least you can see that I have also given some slack for a motor (0.1 mm) to more easily fit into its compartment.
Placing Motor Compartments
Usually quadcopter size is characterized by its diagonal, i.e. the largest
distance between the centers of the propellers (thus the centers of the motors). Our microdrone is small and its diagonal will be only 92 mm (it can fit into a hand). The nearest distance between any two motors is then computed as sqrt(2) * (diagonal / 2). This distance is an edge of a square with 92 mm diagonal. Now, we can easily place the four motors on the vertices of the imaginary square.
diagonal = 92; motors_dist = sqrt(2) * (0.5 * diagonal);
// Half distance between motors half_dist = 0.5 * motors_dist; for (i = [1, -1], j = [1, -1]) { // Place the motors translate([half_dist * i, half_dist * j, 0]) rotate([0, 0, -45 * i * j - 90 * j]) SlotF1607(); }
Note that `for (i = [1, -1], j = [1, -1])` is simply a shortcut of two nested loops, i.e. it is the same as
for (i = [1, -1]) for (j = [1, -1]) // ...
Motors Support
We would like to connect the motors using something like an arc. How to do that? First, create and place a small segment:
translate([41, 0, 0]) square([1.2, 3.6]);
Then, by rotating this segment in space `rotate_extrude`, we obtain a 90-degree arc:
module arc() { rotate_extrude(angle=90, $fn=70) translate([41, 0, 0]) square([1.2, 3.6]); }
Let us link those arcs to the motors.
for (i = [1, -1], j = [1, -1]) { // Place the motors translate([half_dist * i, half_dist * j, 0]) rotate([0, 0, -45 * i * j - 90 * j]) SlotF1607(h=6.5); // Connect the motors translate([half_dist * j * (i + 1), half_dist * j * (i - 1), 0]) rotate([0, 0, 45 * i + 90 * j]) arc(); }
The Platform
By now I have realized that to create the body I could reuse the same method as
for the motor emplacements to create an open box, a box with no top cover. However, the only distinction would be the shape (a Boolean difference between rectangular boxes rather than cylinders). Now, I would like to somehow generalize a method of creating an open box. Ideally, I would like to create boxes of any base shape (circle, square, etc.), thus parametrizing the method by a base shape.
To help me with this idea, OpenSCAD provides `children()` method to access child modules. The new operation could be described as
module openbox(delta=0.8) { difference() { resize_somehow(...) children(); translate([0,0,delta]) children(); } }
So for example the motor compartment could be created simply as
openbox(h=16.5, delta=shell) circle(d=7);
Where `openbox` would receive a 2D shape as a child (a circle, a square, or a
polygon) and transform it into a 3D shape (a box) of a given height using the recipe from above. So how to transform a 2D circle into a 3D cylinder? Using a common method called `linear_extrude`:
linear_extrude(16.5) circle(d=7);
This method is similar to `rotate_extrude` that we used for the arc. However,
it does not rotate the base 2D shape.
Now, how to create a larger version of the cylinder (becoming the shell)? One way to do that would be to use `scale()` or `resize()`. However, a more efficient method would be to operate on the original 2D object, before extruding it (that is actually the reason why our `openbox` was assigned to operate on 2D objects). The `offset()` transformation does exactly what we need to: enlarge the 2D object by a "delta" difference. Therefore, the complete `openbox` module becomes
module openbox(h=10, delta=0.8) { difference() { linear_extrude(h) // Create a larger base by offsetting the child module by delta offset(delta=delta) children(); translate([0,0,delta]) linear_extrude(h) children(); } }
Create a motor compartment as planned
openbox(h=16.5, delta=0.8) circle(d=7);
Here is how to refactor the SlotF1607 module, making use of `openbox`
module SlotF1607(h=16.5, // Module height d=7, // Motor diameter shell=0.8, // Shell thickness slack=0.1 // Some extra space to accommodate a motor ) { difference() { // Motor compartment shell openbox(h=h, delta=shell) circle(d=d + slack); union () { // Bottom hole for motor contacts/wires cylinder(d=6, h=h, center=true); // Wires hole translate([d/4, 0, 0]) cube([d, 2.5, h * 3], center=true); } } }
Similarly, create the body
openbox(h=3.6, delta=0.8) square([46, 23], center=true);
If it is hard to follow this section, note what we do in the line above is the same operation as with the cylinders in the very beginning:
shell=0.8; difference() { cube([46 + 2 * shell, 23 + 2 * shell, 3.6]); translate([0, 0, shell]) cube([46, 23, 3.6]); }
Fine Tuning: Rounded Angles
We are essentially done. However, this design somewhat does not inspire me. Replacing the base square with a rounded one looks like a good idea. After all, we designed `openbox` to support any 2D base shape. Here is a common idiom: create a rounded square as a Minkowski sum.
module rounded_square(dim=[20,20], r=5) { minkowski() { square([dim[0] - 2 * r, dim[1] - 2 * r], center=true); circle(r=r); } }
So here we go:
for (i = [1, -1], j = [1, -1]) { // Place the motors translate([half_dist * i, half_dist * j, 0]) rotate([0, 0, -45 * i * j - 90 * j]) SlotF1607(h=6.5); // Connect the motors translate([half_dist * j * (i + 1), half_dist * j * (i - 1), 0]) rotate([0, 0, 45 * i + 90 * j]) arc(); } openbox(h=3.6, delta=0.8) rounded_square([46, 23]);
Much better!
Fine Tuning: Final Touch
Now, I would like to shave off a bit of weight if possible. So I will introduce some holes as e.g. in the honeycomb pattern. I will generate an array of hexagonal cylinders and subtract it from the platform. A hexagonal cylinder is simply a cylinder with six fragments, i.e. `cylinder($fn=6, …);`. Here is an array of those generated with two nested loops `for (i = [-M:M], j = [-N:N])`:
module honey_comb(h=10, M=10, N=4, d1=4, d2=4.6) { for (i = [-M:M], j = [-N:N]) { // Shift the row by d1/4 if (abs(i) % 2 == 0) translate([i * d1, j * d2 + d1/4, -h]) cylinder(d = d1, h = h * 2, $fn=6); // Shift the row by -d1/4 else translate([i * d1, j * d2 - d1/4, -h]) cylinder(d = d1, h = h * 2, $fn=6); } }
Where `abs(i) % 2 == 0` simply checks if index `i` is an even value so that odd and even rows are shifted by a different amount.
Now I use an `intersection` with another shape to limit the span of the honeycomb pattern.
intersection() { honey_comb(h=11, M=6, N=4, d1=4.1, d2=4.9); // Limited by this volume translate([0,0,-0.5]) linear_extrude(10) rounded_square([dim[0]-2.5, dim[1]-2.5], r=6); }
Finally, I subtract the above pattern and some side holes.
// The platform module platform(dim=[46, 23], shell=0.8) { difference() { openbox(h=3.6, delta=0.8) rounded_square(dim); union () { // Honey-comb patterned floor intersection() { honey_comb(h=11, M=6, N=4, d1=4.1, d2=4.9); // Limited by this volume translate([0,0,-0.5]) linear_extrude(10) rounded_square([dim[0]-2.5, dim[1]-2.5], r=6); } // Side holes for (i = [-1,1]) translate([12.5 * i, 0, shell + 4]) cube([11, 40, 8], center=true); } } } // The main module module beatle1() { for (i = [1, -1], j = [1, -1]) { // Place the motors translate([half_dist * i, half_dist * j, 0]) rotate([0, 0, -45 * i * j - 90 * j]) SlotF1607(h=6.5); // Connect the motors translate([half_dist * j * (i + 1), half_dist * j * (i - 1), 0]) rotate([0, 0, 45 * i + 90 * j]) arc(); } platform(); } beatle1();
That was quite easy. Wasn’t it?
Fabrication
Next, open your favorite slicer software that often comes with a 3D printer.
You will need to specify 0.2 mm layer height, three perimeters, and 30% infill. After slicing (transforming into a series of commands that 3D printer can perform) the design can be inspected layer by layer and printed.
To build a complete micro drone, we need to solder motors to the flight controller. Attention: the motors are rotating in opposite directions (see schema by Oscar Liang). Also note that propellers are different. In order to match the propellers with the rotation direction, keep in mind that the propellers should push down the air. Motor wires could be easily detached from the controller. To prevent this it is a good idea to fix the wires to the frame.
The instructable is based on this post. I also made the complete design available on Thingiverse. Please let me know how can I improve this document for you!