[applause] Hi there, how are you doing? Thank you so much for coming. So, I am here to talk about
using Python to generate designs for 3D printers and laser cutters,
but first I want to talk about myself and introduce myself. That's my email address
and my GitHub repository. So, I work at a start-up
in Boston called Ginkgo Bioworks. We apply techniques
from synthetic biology and genetic engineering
to build custom organisms for our customers. We build thousands
of custom strains, and to do this at scale,
we rely heavily on Python to help us design, track,
and analyze our engineered samples. And if you're interested
about Ginkgo, you can learn more about us
at ginkgobioworks.com. We are hiring. In my spare time,
I like to explore a lot of different hobbies,
and that includes things like photography and gardening
and cycling and cooking, electronics and making art. And for each one of my hobbies,
I've at least written like a handful of Python scripts
to facilitate it one way or another. So here's a quick example: in my backyard,
I have a Davis weather station. This transmits weather data
wirelessly to a Raspberry Pi in my house, and I have
another Raspberry Pi in my basement that monitors this data
and controls a set of relays that switch on sprinklers
to water the garden. So Python for me, it's not
just a programming language. It's one of the primary means I use
to express myself creatively. But as powerful as Python is,
programming by its very nature is not a physical medium. Frederick P. Brooks wrote
one of my favorite quotes about computer programming
in his book "The Mythical Man-Month." (reading quote) And the world is filled with these
amazing but nebulous castles but we can't really appreciate them
without the aid of a computer. You can't share your code
like you would a painting, or a sculpture,
or a well-cooked meal. And, you know, to be honest,
I realize that this is not true. Like, we use software to manipulate
our physical world every day. Our computers produce
sound and light and they churn out
printed documents. There are many ways
that you can write code to affect the physical world. And that's the core
of what I want to talk about. But first, a little history. Before there were computers,
people had to make things by hand. The period between
the late 19th century and the middle of the 20th century
was collectively known as the Machine Age. And during this time,
we perfected the art of building parts
at an industrial scale using a process called
subtractive manufacturing. This includes techniques such as:
milling, turning, boring, broaching, sawing,
reaming, tapping. The general idea was to shape
bulk stock into some kind of part by removing material
with incredible precision. But after the 1950s,
the world entered the Atomic Age and ushered in
the digital computer. And during the 1940s and 50s,
existing tools like mills and lathes were connected
to electric motors that were controlled
by punch tape. This was the first step towards
automation of these machine tools. And as computers evolved
in sophistication, it spawned a new field
of fabrication called computer numerical control,
also known as CNC. So today, computer-controlled
automation is ubiquitous throughout all areas
of manufacturing. Not only has the computer hardware
and software programming evolved to such a point
of sophistication, but there are new manufacturing tools
and processes that had never existed just a few decades prior. This includes things like
plasma cutters and water jets and 5-axis milling machines,
lithography, and two of my personal favorites:
laser cutters and 3D printers. So, we're going to examine each one
of these technologies individually, and then we're going to discuss
how we can use Python to generate designs
for these tools. So first, laser cutters. Laser cutters are devices
that utilize high-powered lasers to etch or cut a variety
of different materials. Most commercially available
laser cutters are capable of cutting and etching
paper or wood, plastic, leather, fabric,
up to a certain thickness. And the laser tube itself
is static to the device, typically mounted towards
the back of the machine. Carefully positioned mirrors
bounce the laser light to the laser head,
and the laser head itself is composed of mirrors and lenses
that focus the laser beam onto the target material. Stepper motors then move
the laser head in the X and Y plane parallel to the work material,
thus allowing the laser to trace out the contours of a given design. Laser cutters are incredibly precise
and they're capable of producing just really complex and intricate
detail in your design. Digital design for laser cutters
though, typically start as vector graphics. This is, you know, design programs
like Adobe Illustrator and Inkscape are vector illustrator packages. This is in contrast to programs
like the GIMP or Photoshop which are raster or bitmap
oriented graphics packages. Vector graphics make it easy
for the software controlling the motion of the laser cutter to translate
your graphics into motion. The process of creating
laser cut designs is relatively straightforward. After you think about
what your design should look like, you need to pick the material
that you want to use and the size. Generally speaking,
if you're cutting with a laser cutter,
thinner is better than thicker. Your design should then be sized
according to the constraints of the material
you're cutting out. But with vector graphics
you can scale your designs without losing any fidelity
of your design. Most laser cutter software
then requires you to indicate which parts of your design
are meant to be cut versus which should be etched. This can be achieved
with a color of the line, for example, red for cut
or blue for etch. And then when you're ready
to execute your cut, you position your material
on the laser bed, and you focus the laser beam,
and you upload your design file. Every laser cutter, to be honest,
is a little different, so the specifics of
how that actually gets done is dictated by the company
that makes that specific cutter. So, you can upload your designs
as PDF or EPS, but I personally prefer SVG. SVG files are XML documents
and a closely-related cousin to HTML. HTML and SVG share
a lot of attribute names for various tags, like width,
height, style, and border. They share style syntax as well,
and later revisions of SVG actually support
cascading style sheets. This is a simple example
of an SVG document. You can see the two tags:
rec for rectangle, and circ for circle. The rectangle tag
takes an XY position to define its top-left corner
and a width and height value to define its size. The circle, on the other hand,
requires an x and y coordinate to define its center,
and another value for its radius. And each of these objects
take parameters that define how the shape is stroked and filled,
that is, with what color. But as you can see, you can get
relatively complex designs with just a few lines of code
with an SVG. My personal favorite
feature of SVG are paths. A path is simply a list
of connected line segments that are used to build
complex polygons. A path segment can be
a straight line or a curve spline
with control points. Within the SVG document,
the path is defined by a string of characters. It's broken up into
single letter commands like m for move
or l for line, and then two or more numbers
that represent the coordinate of that command. You can do a lot
with just circles and squares, but paths allow you to build
incredibly complex shapes. And in this example,
I just rattled off a few random points
to make this squiggly line. So, for this talk I wrote
a Python program to generate a laser-cuttable
cube or box that uses finger joints. Even though this design
originates in 2D space, when you put it together
like a puzzle it produces
a three-dimensional shape. The program itself is
a few hundred lines of code so we won't be able
to discuss it in its entirety, but you can go check out
my GitHub repository after this talk,
and look at the code, and look at the various options
that allow you to change its design. I brought a bunch of examples
as well, and so if you come find me, I can show them to you. And I'm gonna auction these off
later at the PyLadies auction. So, this is what
one of the generated designs looks like that is sent verbatim
to the laser cutting control software. You can see
that the layout of the design packs the faces closely together
to minimize the overall waste of the material. And you can see that it's not
the same face over and over again. There are slight differences
between each of the individual faces. And that's to help
the puzzle-like way that it fits together. And so this is the result
of what you get when you cut
that design on wood. You can see the scorch marks
caused by small flare-ups as the material briefly ignites
from the laser. As a bonus the board has this
nice, refreshing burnt wood smell. Since the cube fits together
like a puzzle, the edges of each face
must interlock. I think of these edges as being
either positive or negative, dependent upon whether
they have a outer edge to them or an inner edge to them. And I've color coded them
to distinguish this feature. So in this case, red is positive
and green is negative. So, as we kind of dial in,
we can just think about a single edge on a single face,
and consider the code that we would need to write
in order to generate it. The width of the material
dictates the height of each individual finger,
and the length of the edge combined with the number of fingers
that you want in your design dictates the overall width
of the finger itself. And so from these
configurable parameters, we can write a function
to draw a single edge. And this is
what that code looks like. This function takes
the size of a cube face as a tuple, the number of fingers in an edge,
the width of a single finger, and the thickness of the material, and it calculates
various geometrical offsets. First, we use the size of the face
in order to find its center. Along with the number of fingers
in the finger width, we use the center position then
to calculate where our first point in the edge line should occur. We then build two lists
of positional offsets, one for the finger width,
and the other for the finger depth. And we iterate through each point
along the edge, calculating the offsets for each. The code exploits the fact
that every other point moves forward through the edge,
and every second point raises the edge
and every fourth point lowers it. So we use a modulus operator
to replay those offsets as we build the edge profile. And here is an example
of how you would call that previous function. Since the previous function
was a generator that returns a list of positions, the caller takes those points
and translates them into a string that is formatted as an SVG path. You can note that
the first command is an M command because we want to move
to that position. And then it's followed
by L commands to actually draw those connected line segments. And that's the result
of what we've drawn. This is obviously only a small piece
of the overall box generator, but it's central to the design. The code is object-oriented
and relatively easy to follow. You can configure and customize it
in many different ways, such as the size of the box,
the thickness of the material, and the designs
on the box faces themselves. So for example,
since the box generator itself has a base class that defines
a geometric rules for each face, you can inherit from this class
and hook into it's rendering method. In this example, I've added
a Fermat's spiral. This is a simple mathematical function
that generates a pattern that is reminiscent of the pattern
of seeds you would find on the face of a sunflower. And this is the code that is used
in order to generate that. Rather than going through this
in detail, I just want to highlight this idea that you can come up with
interesting artifacts like that and embed it in part of --
in your overall larger design. It's very easy to do,
once you figure out kind of the base of your object,
to add these kinds of artifacts that give your design more flavor. And this is the resultant image
that is generated from that. So, SVG makes it really easy
to layer in new elements and add to the design
without requiring you to change the overall structure
of the SVG document itself. Coupled with Python,
it's the perfect technology to express
your laser-cuttable designs. Whoops. Alright. So, 3D printers. 3D printers are devices
that can build three-dimensional objects. They range in price
and sophistication, but the most common
3D printers available are known as
fused deposition models. These work by breaking down
three-dimensional objects into 2D slices that, when stacked
one on top of the other, will reconstruct the geometry
of the three-dimensional object. FDM printers, specifically,
work by extruding plastics at really high temperatures. But unlike laser cutters,
3D printers work in three axes instead of two. The X and Y axes are utilized
by the printhead to deposit the material
in a desired shape, and the Z axis is then used
to advance the model to the next
two-dimensional slice. This is a high-level
design pipeline for 3D printers. Most 3D printing software
consumes STL files and produce
what is known as GCODE files. But STL files are not easy
to generate by hand since they actually represent
the three-dimensional object in a triangle mesh form. Personally, I don't think about
my three-dimensional designs as a mesh of triangles. I like to think about them
as solid objects. About five years ago
my girlfriend and I purchased our first 3D printer,
and we were so excited about it that we were obsessed about
all the things that we were going to design
and make on it. But I was immediately frustrated
with the standard tools out there that people typically used
to design CAD models for printing. You know, I'd spend hours
in programs like SketchUp building up a complex design
only to realize I needed to change something
core to the model. Most of the design tools
do not make it easy for you to make these kinds
of drastic changes. It's kind of like painting
a family portrait and realizing
you left out your brother. So, there are more sophisticated
3D modelers out there, including some
that are parametric. But most are expensive
or only run in Windows or are difficult to learn,
or typically all three. So I looked around to find
a programmatic solution that I would find
more comfortable and that's how I discovered
something called OpenSCAD. OpenSCAD utilizes
constructive solid geometry. The idea is to build your objects
from two-dimensional and three-dimensional primitives
such as cubes, cylinders, and spheres. You position these objects
in space and then you define boolean operations
between them. The most common
boolean operation is union, to join two or more solids
together as one. And then there is difference,
which is used to subtract one or more solids from another. So for example, let's just take
a drinking glass. We can construct it
with just two cylinders. The first cylinder -- sorry, the top got cut off
but we'll see the code later. The first cylinder describes
the outside surface and the second describes
the empty volume inside. Using OpenSCAD, we would define
the first cylinder with a second cylinder inside. The inside cylinder
would then be offset in the Z axis, or the up axis,
and would have a smaller radius than the outer cylinder. We would then subtract
that inner cylinder from the outer cylinder
to create that empty envelope. In order for this to work,
we have to make sure that it leaves the floor of the glass
but creates the mouth as well, and that's why we do the offset. So this is what
your two cylinders would look like. And you can see
in the third line of code, there's a translate operation. And that is what moves
that inner cylinder up to create the floor of the glass
and the mouth of the glass. Right now I have this
as a union of two objects to highlight the fact that these
two cylinders are inset, but by changing that top union
to a difference, we then create the empty volume
that we're aiming for. OpenSCAD does all of the hard,
complicated math to calculate the mesh
for these objects, freeing us up to think about
how to construct our models with just primitive shapes. I think it's impressive
to consider what we can build with just four lines of code. But the scripting language
for OpenSCAD is relatively simple in and of itself,
and doesn't really provide a lot of the features
that we know and love from Python. But with the simplicity
of OpenSCAD in our favor, we can easily then generate
OpenSCAD from Python. So, for a more complicated example,
we're going to consider a flower pot. Flower pots are similar
to drinking glasses, but they also have
a few distinct features. First, most flower pots
are wider at the top and smaller at the bottom. Although we think about the shape
as a cone, it's often described as a cylinder in OpenSCAD
because you can define a cylinder with two different radiuses
for each end. Second, they usually have
a hole at the bottom to facilitate drainage. And finally, they often provide
a lipped collar at the top to make it easy to hold
and move the pot around. So now that we have a feel
for OpenSCAD syntax, let's talk about
how we can generate this design from Python. There are a few different
Python libraries that allow you to build OpenSCAD
syntax from Python, including a library that I've written
called Python SCAD. Most of these libraries
work in very similar ways, wrapping OpenSCAD definitions
with Python classes. For my demo,
I'll be using my library but you can accomplish
the same thing with any of the other
alternative libraries out there. So, most of my SCAD objects
that I write in Python start out like this, with a series
of parametric variables that help define the physical
constraints of the object. I try to write a few top-level
variables that are designed to be flexible, and then compute
other variable values based on those initial values. In this example,
many of the variables for the flower pot are derived
from the flowerpot's overall height. This makes it easy to change
the overall size of the flower pot without having to change
each individual variable. You can also see that I have --
as an example, I have ratios in there
that define, for example, the top radius
versus the bottom radius. You know, I went around measuring
flower pots around my house and found that it was
typically about a .6 ratio. And along with things
like the thickness or the wall thickness
of the pot itself, because we have to
calculate our offsets in order to do the subtraction. So this is all the code
that is required to then produce that pot. It's, to be honest, much simpler
than the cube for the laser cutter. It's pretty boring, actually. We start from the outside
and add other cylinders to carve out the spaces we need. It's built entirely
with the cylinder primitive along with unions
and translations. Really the only hard part
is imagining your model and then breaking it down
into primitive solids. Once you've done this,
building the design and code is incredibly straightforward. So, this is my printer at home
building a 2.5 inch flower pot which is right here. It took about two hours to print,
but one thing you'll notice is that it's printing
an outer wall that's actually not
part of the design. This wall is generated
by the printer software and is known as
a support material. The lip of the flowerpot
overhangs in space and without that support material,
the printer wouldn't be able to successfully print
that overhang. But you can just tear it off
once the print is done. And there's the finished result. So, now I'm going to talk about
two projects I have done with laser cutters
and 3D printers that are more complicated,
and the code is available for these projects. But it's to kind of
whet your appetite of, beyond these simple examples
what else can you do with it? So to start off first is
my snowflake generator. This project, my girlfriend
and I started about four years ago. We were trying to figure out
what to make our friends and family for the holidays. And Rachel found
this amazing paper that describes a physical model
to simulate the growth of snowflakes. We translated the math
from this paper into Python code and proceeded to make
personalized snowflakes for everyone on our gift list. The model works
at the mesoscopic level, which is to say it models
a collection of molecules, specifically water molecules
as an undefined unit. And it starts off first
by constructing a hexagonal grid. The grid is then populated
with a homogeneous field of water molecules. And these water molecules
can move from one neighboring cell to another and can switch
between three defined states: vapor, boundary, or frozen. The boundary state is often used
to describe water that is neither vaporous or frozen, but caught
in between those two states. The initial field
of water molecules are set to a vaporous state,
except for the cell in the middle, which is initialized
as a frozen state. And then, from there,
the simulation runs and the snowflake
begins to form. The model takes eight
different parameters which dictate the behavior
of these individual steps in the algorithm. So each cell does
these individual calculations for its own state. It first figures out how
the vapor of the cell should move. And then it figures out
if some of it should freeze to the boundary vapor. And a portion of the frozen
boundary cells then attach to the body of the snowflake. And then a certain portion
of them melt off. And finally, as a parameter
for noise, which I think is really beautiful, it adds
just a little bit of randomness to the overall simulation. And what you end up are not
perfectly symmetrical snowflakes, but snowflakes with slight defects
with respect to their individual arms. So, from a grid perspective,
as the simulation progresses, the snowflake crystal begins
to grow out from its initial seed, so you can see
the frozen state in the middle, and then the boundary seeds
around it. And the program works like
a cellular automata simulation. Each cell inspects its neighbors
and calculates its changes based on the parameters But because there's hundreds
of thousands of cells, the simulation is
computationally intensive, taking hours to run. In order to generate
the hundred snowflakes we made as a gift, actually, we generated all
of our snowflakes in the cloud. [laughter] [applause] So, the result of this simulation
is a complex bitmap. But instead of capturing
red green blue intensities on a Cartesian grid,
this bitmap stores the density of the frozen water molecules
within a hexagonal grid. When the snowflake reaches
a certain predetermined size, the simulation stops
and the program proceeds to translate that snowflake
into SVG files. Two SVG files
are produced and merged. The first SVG file is
a representation of the densest bands
of frozen water molecules in the snowflake. That is where the most common
abundance of water that froze, and there are these bands
of density that you can see. And the second SVG
actually defines the outline of the snowflake, and these two files are merged
into a single SVG and then sent
to the laser cutter. So, I have a kind of a cool video
that just describes this whole process. One thing that really astounds me
about this model is that it can generate just
an amazing variety of different kinds of snowflakes. And very much with each
not looking like the last. So this is -- I ran the simulation
saving an image of the snowflake at every step, so this shows you
the overall growth of it. You can see the black aura
around it, and that's actually the depleted vapor
that it's sucking into the body of the snowflake, while the gray area
is still vaporous water. And here we are etching
and cutting one of the snowflakes. So, you can see right here
the laser cutter is in an etching mode, where it is
just pulsing the laser and just ablating the surface
of the plastic off to make a depression
in the plastic but then not actually cut it. And then once it's done,
it does the cutting step, which allows us
to remove the snowflake. And again, I have brought
examples of these guys, so if you want to, come take
a peek at them after the talk. Alright, so the other example
that I want to show you is something
that I called Rockit. So, this is a model rocket
construction kit. You know, this is kind of
the first project I did with OpenSCAD and Python,
and I wanted to make something functional, right? I wanted to be able to print
something off my printer and have it
actually do something. And so I made this model rocket
generator that can design and print a range
of different rockets and rocket types. So if you're not familiar
with model rocketry, you should know that there are
a range of different engine sizes. And these engines are made
of solid propellant packed into a cardboard tube. The sizes of these engines
vary in length and diameter, requiring different-sized
engine holders to start a design. When you start a design,
you first select an engine and then Rockit will calculate
a bunch of different parameters for the rocket
based on that engine size. Another neat feature of Rockit
is that it uses these coupling sleeves
that allow you to snap together the rocket like Legos. I mean, you can literally just
print this off your printer, snap it together
and then launch it. But I recommend using glue because it will probably
come apart in flight. [laughter] And you can even print the base
with that coupling sleeve and that will allow you
to make multistage rockets. Rockit makes it very easy
to change different aspects of your design. For example, you can swap in
different kinds of nose cones, or you can add or remove fins,
or one of my favorite features is to tilt the fins so that when
the rocket is launched, it rifles up into the sky. But what I think is
really fantastic about this is that you can print two
very similar rocket designs with a slight tweak between them
and they'll be very -- it's a very reproducible process. So you can empirically evaluate
how you have changed the performance of your design. So, my friend Adam
videotaped this one launch, and it's unfortunately
the only video footage I have, and it's a pretty
disastrous launch. But it does work. I believe this is
one of the ones that had spiral, so it spiraled up into the air. But the weight ratio
to the engine size was not calibrated, and so it also then
promptly took a nosedive. But that's the best part -- I mean, these rockets, to be honest,
they're not the most robust thing. I mean, it's plastic,
and plastic doesn't like heat, and so you're likely to melt them,
but I say who cares? Just go home and print
some more, you know? You'll definitely at least
get a few flights out of it. But yeah, I just -- what I think
is just so neat about this is that you can print something
off your printer and stuff a rocket engine in it
and it will fly. Anyway,
you may be asking yourself, how do I get access
to these tools? So I realize that not everybody
has these at their disposal. And in Boston, where I'm from,
there are a number of local maker spaces
that provide access to 3D printers and laser cutters. Some public libraries
have also booted up their own maker spaces
to provide access to these tools. And if you can't find
anything local, you can always use popular
internet-based service providers such as Ponoko or Shapeways. For example, I got all
of my materials cut at Ponoko before I came to this talk. But the whole field
is really rapidly changing and new tools
are coming out every year. And as these tools advance,
the total cost of ownership comes down in price. These are the relevant GitHub URLs
for all the various software that I've written. The top one is
a mirror of this talk. But you can also find
my snowflake generator, the rocket generator, and the Python SCAD
library there. And that's it,
thank you very much. [applause] (moderator)
So, a few minutes for questions. If you have any,
come to the microphones please. (audience member)
I'm curious as to why you didn't print
your pot upside down. (Giles Hall)
That's a great question. The reason is that, um -- the -- the flatness
of the bottom of the pot would then be the overhang
as opposed to the lip. To be honest, it's probably
six of one, half-dozen of the other. But you would imagine
that it would have to print a scaffolding
into the center of the pot, and I find that to dig out
support material is harder than just being able to rip it, so that's why I chose
that orientation. (audience member)
Thanks. (moderator)
So if there are no more questions, let's thank the speaker again. [applause]