Monday, January 16, 2017

Robotic Painting with a Line of Lights

This post documents a method of generating light paintings using a robot moving a linear array of lights through space. The robot moves a simple stick tool which contains 60 lights stretched along its 1 meter length. Each light can be individually controlled, any one of 16 million colors, and that color can vary over time.

The image is recorded using a camera which keeps the shutter open during the entire motion of the robot. Everything happens in a very dark room so the great majority of the light collected comes from the lights only. The result is a single image showing the entire path of the line of lights.

Grasshopper Definition

The robot motion is controlled by a simple Grasshopper definition using the plug-in Kuka|prc. The motion is driven by an input curve and a few parameters described below.

There are two parts to the definition. One simulates and generates the robot code. You work with this part of the definition to assure that the robot can reach the entire curve without hitting joint rotation limits and that the tool does not collide with the robot table.

The other part of the definition is used to simulate the light effect prior to running on the robot. This is important because it is impossible to visualize the path of the lights as they rotate traveling along the input curve.

See the post Working with Planes in Kuka | prc for information on various methods of dividing curves and driving the robot.


The adjustable parameters are as follows:
  • Curve: The curve the robot follows. The robot face plate and tool rotate so the line of lights is always perpendicular to the curve at every point. It's this twisting motion of the line which generates the visual interest. 
  • Curve Divisions: The entire length of the curve is divided into the specified number of segments. By varying this parameter you can get a great variety of outputs. In general, the most interesting results are obtained using low values. 
  • Tool Length: This is fixed for the Taubman College tool which is 1 Meter long. 
  • Lights on Tool: To simulate accurately you need to tell Grasshopper how many lights will be illuminated on the stick. This can be either 15, 30 or 60. The actual number of lights used is set on the tool itself. 

The Curve obviously has a major impact. But it's surprising that using different curves with low division counts you can get some amazing effects. Here are a few sample curves drawn in Rhino:

It's of course also possible to wire in a parametric curve generated by Grasshopper.

The strip of LEDs has 60 lights per meter which is the length of the stick. The Arduino code allows you to set the number of LEDs which are illuminated. By using every every 1/12th you can have 5 lights show along the length. Using 1/4th you can have 15 as shown below:

Every other LED produces 30 and every LED is 60:

Here's are examples using the same curve with a different division count:

Here's a different curve with two different division counts:

The End Effector

The tool attached to the robot is basically a stick made of 1/2" Baltic Birch plywood. There's a small box to house the electronics. Milled into the stick are some grooves for the light strip and the wires.

The lights are NeoPixel strips made by Adafruit. Everything is driven by an Arduino.
There are a few simple controls - two push buttons, and three knobs:

Here's a video demo of the controls (description below):

Push-Button 1

Use this to change between the 5 different light effects. Press the button to change to the next mode - the sequence is as follows:
  1. Constant color for all lights - same over time. Use Knob 1 to set the fixed color. 
  2. Unique color for all lights - same over time. Use Knob 1 to shift the colors along the line of lights. 
  3. Unique color for all lights - rotates along the strip over time. Use Knob 1 to shift the colors along the lights. Use Knob 2 to set the rate of change. 
  4. Random colors for all lights - same over time. 
  5. Random colors for all lights, rotates along the strip over time. Use Knob 2 to set the rate of change. 

Push-Button 2

Use this to control the number of lights which are illuminated on the stick. As you press the button the number of lights lit will switch as follows:
  • 5 LEDs 
  • 15 LEDs 
  • 30 LEDs 
  • 60 LEDs

Knob 1

Changes the color of each light. Rotating the knob moves the lights through hue space. All the way counter-clockwise is 0, fully clockwise is 360, where:

0=Red, 60=Yellow, 120=Green, 180=Cyan, 240=Blue, 300=Magenta, 360=0=Red.

How the change effects each light depends on push button 1 (see above).

Knob 2

Use this to change the intensity (brightness) of the lights. All the way to the left is dimmest, all the way to the right - don sunglasses.

Knob 3

Use this knob to specify the rate of change of the light colors over time. Slowest is all the way counter-clockwise. Fastest is fully clockwise.

The Robot

These examples were generated on a small Kuka Agilus robot. Like all robots it has a limited reach and range of motion. There are a few controls in Grasshopper you can use to allow the robot to reach every point on the curve.

Initial Position: This is key. You need to pose the robot in a neutral position for the start of the motion. None of the joints should be near their limits and it should be roughly centered on your path. You set this in the Kuka | prc Settings, on the Advanced Page.

Middle Point Location: This is the most important tool for solving joint limit problems. If you encounter a position in the path where a joint turns red, leave the simulation slider where that joint is red, and move the middle point location a bit. Usually you can find a spot where the joint is no longer in a limit. This can be up or down, or closer or farther from the robot. Note: There are curves which are impossible to fully reach. But if your curves are not larger than the samples provided you'll probably be able to find a position which works.

Arduino Hardware and Software Details

This section describes the wiring and software setup.

Below is the prototype I built using components I had on hand to test with. A slide potentiometer for the hue selection, a cheap pot for knob 2, one nice push button and one piece of junk. These were replaced with better components in the final tool.

The NeoPixels need current. 60 pixels at full brightness need almost 4 amps. An Arduino supplies only 0.5 amps as does a 9V battery. So an external power supply is necessary. This is the one I prefer: 5V 4A (4000mA) switching power supply.

The color is computed in Hue space but needs to be provided to the LEDs as RGB values. I used some great code I found online to do this: Why every LED light should be using HSI colorspace.

The prototype used an Arduino Uno. The final version needed a smaller footprint micro-controller so I used an Arduino Micro.

The face plates are laser cut acrylic. I got the buttons here and the pots here.

My research assistant Celine Schlueter did all the soldering:


The process needs some more development but I like the initial tests of this new tool.

For some other image painting tests see this post.

Thursday, December 15, 2016

Parametric Surfaces in Rhino via the Math Plug-In

The Math Plug-In is the excellent work of Jess Maertterer (here's his web site). The plug-in calculates smooth curves and surfaces based on parametric equations.

You can download it here: Math Plug-In. Note: When you install the plug-in you'll need to Unblock it first.


Once installed there are a few new Rhino commands you have available:
  • MathLibrary
  • MathCurve
  • MathSurface
  • MathEditObject
  • MathSaveObject


This brings up a dialog to let you select from some pre-defined surfaces, or those you've added to the library with MathSaveObject (see below). You can choose from a curve or surface library.

When you click on an image it brings up an editor to let you see the functions, min and max u and v values, and the point counts in u and v.

When you press OK it creates that object. You can always edit the object using the MathEditObject command.


Brings up the interface to let you define a curve using functions.


Brings up the interface to let you define a surface using functions.


Ask you to select a math object. Once you do you can edit its definition again. After you hit OK it is updated.


This lets you save an object so it appears in the curve or surface library.

Function Reference

The functions you can use are referenced here:

Pasta Surfaces!

I had some fun with this plug-in in conjunction with a book on the mathematics of various pasta shapes: Pasta by Design. The book gives the equations and limits for many forms of pasta. The formulas can be entered into the Math Plug-In. The only change you need to make is to substitute the variable name 'u' for 'i' and 'v' for 'j'. Also, make sure you use enough steps in U and V. The defaults are low and you'll likely need higher values.

Here's a spiral shaped pasta known as Buccoli:

Because it is a Rhino surface you can do all the things you can usually do - solidify, panelize, cytoskeleton, etc.

Wednesday, December 7, 2016

ZBrush Renders of a Figure Sculpt

A few screen grabs using various viewport shaders on the figure sculpture I'm working on...


When I come up with a new, interesting way to fabricate this I'll post again.

Here are a few methods of ZBrush model fabrication I've posted previously: 

Sunday, November 20, 2016

Kangaroo Physics Simulation for Grasshopper

This topic is an introduction to the Kangaroo plug-in for Grasshopper. Kangaroo is a set of Grasshopper components for form-finding, physics simulation, and geometric constraint solving.


Kangaroo is fantastic - but it is something of a moving target. It's under development and has gone through a total rewrite. The new version, which is a huge step forward, still is assisted in some definitions with the earlier version. So, as of this writing (11/2016) you still want to install both. This will give you the ability to explore the largest set of sample files.

You can download the various versions of Kangaroo here:

Grab both the latest version, currently 2.14, and the earlier 0.099. Then follow the installations instructions in each Zip file:

With Kangaroo installed you are ready to build some definitions. As an easily accessible reference here's the Kangaroo PDF Help File.

First Example - Project to Plane

As a first example let's look at simply moving a set of vertices onto a plane. You don't need Kangaroo for this - because you can do it in Rhino. But it's a good example to get going and explain some basics.

The first two components on the left, Box 2Pt and Populate 3D define a box and populate it with random points.

There are two Kangaroo components in this definition. One is a Goal and the other is the Solver.

The goal in this case is OnPlane. This moves a point to a given plane (and keeps it there). If you supply many points they are all pulled down to the plane. There are many goals supplied by Kangaroo. In general they take the current position of some points and output some target positions it "wants" the input points to move to. You can supply as many goals as you like and Kangaroo will adjust the points in order to meet all the goals.

The other component here is the Kangaroo Solver. This is the one which collects all the goals and solves the system. It outputs the "solved" vertex locations. In this particular example it outputs the points as moved to the plane.

There is also a Button component wired into the Reset socket. This resets the system and begins solving it again. The solver automatically runs over and over until it converges at a solution. Then it stops automatically. In some cases, such as this simple example, it converges so fast it stops immediately. That's because it can be mathematically calculated to instantly move points onto a plane. Other kinds of goals take iterations. For example making connected polygons all planar. That's an example we'll look at later - it often takes a few seconds to converge to a solution. Because the solver loops over and over converging towards a solution you can see it gradually solve the system.

In the simple definition above the Vertices output from the solver are wired into a Delaunay Mesh component which generates a mesh between all the points. If you press and hold the Reset button you'll see the mesh drawn through the original points. When you release the button the system is solved and the mesh is drawn through the planar points.

Meshed points before solution

Meshed points after being moved onto the ground plane

Catenary Mesh

This definition is slightly more complex but is much more useful. It's a form finding technique used to generate structures in pure tension or compression. The term catenary refers to a curve formed by a string, or chain hanging freely from two points and forming a U shape.

This can be expanded to process the vertices of a mesh into a three-dimensional form:

The definition operates on a mesh. In this example the start mesh is a rectangular grid as seen on the ground plane. Shown above it is the resulting catenary form as generated by Kangaroo:

The definition is below. Download Here.

It has three goals:
  • Anchor: This will keep a point in its original location. This is used to lock the corners of the mesh in place. 
  • Length: This goal tries to keep two points (line endpoints) at a given distance form each other. With a higher Strength specified the points move less. 
  • Load: This goal applies a force to the points. The force is specified as a vector and the length of the vector is the magnitude of the applied load. 
You can add a slider to the Strength component to control the stretch of the form. You can also affect that using the magnitude of the vector wired into the Load component. For example wire a slider into the Factor socket of the Unit Z vector.

You can bake the O output of the Solver. This generates the set of lines of the form. You can use the Weaverbird Mesh From Lines component to create a Rhino mesh. Then use other tools such as Rhino's OffsetMesh command to turn the result into a mesh solid suitable for 3D printing or rendering.

This basic definition can be modified to use your own mesh. Here's an example of using a few tools to build a base mesh.

Use the Rhino menu Mesh > Polygon Mesh Primitives and choose something like a Truncated Cone.

Explode that mesh and delete the top and bottom faces:

Use the ProjectToCPlane command make the mesh flat: Mirror the mesh and Join it together into one.

Press F10 to turn on the mesh vertices, then select two and use the Gumball to scale them with a value of 0. Do this for both side:

You can use the MeshRepair command to weld the mesh together, leaving only the outside edges as naked.

This mesh can be wired into the definition. It works nicely with Weaverbird to subdivide the mesh prior to running. More information on LunchBox and Weaverbird can be found in Working with Meshes in Rhino and Grasshopper.

This results in a structure like this:

When you Bake the output of the Kangaroo Solver is only lines. It doesn't output a mesh.

To convert it to a mesh you can use a Curve component to collect the lines then the Weaverbird Mesh From Lines (Weave Back) component to generate the mesh:

If you bake the output of the Mesh From Lines you'll get a proper Rhino mesh.

Tensile Forces

Similar to the example above, but not using a Load, you can explore some tensile forces on meshes.

By using a few anchor points on triangle meshes you can experiment with a surface that behaves a little like bending fabric. You can make a few Point entities that are snapped onto the mesh vertices. Kangaroo will find the matching mesh verts and anchor those. If you add the Grab component you can pull the points interactively to shape the form.

Here's the definition. Download Here. You can download a sample Rhino 3dm file here.

By holding the Alt key down and dragging on vertices in the mesh you can pull them:

Another use for tensile forces is to smooth, or relax meshes. The second definition in the above file does that.

These work best with Quad meshes - meshes composed of four sided polygons rather than the triangle meshes normally generated by Rhino. As of this writing (11/2016) if you are using the Rhino 6 WIP you can use the QuadMesh command to generate these from polysurfaces. Otherwise I'd recommend using a better quad mesh modeler like 3ds max, Maya, modo or ZBrush.

The original mesh is subdivided using Weaverbird. In this case using Catmull-Clark. The Weaverbird Join Meshes and Weld component makes sure there are no duplicate edges. The Weaverbird Mesh Edges component will output all the edges. These are wired into a Line component to ensure sure they are line entities. Then the Curve Length, multiplied by a factor, is wired into the Length goal (of Kangaroo).

The Weaverbird Naked Boundary component outputs all the open edge curves. These are Exploded then using the End Points component the start point of the lines are found. These become Anchor goals. By altering the strength of the anchor goal the form can remain closer to the original mesh or highly relaxed as shown below.

Circle Packing

This definition is a simple example that uses the SphereCollide Kangaroo component to pack circles onto a surface. The circles can be offset and extruded to achieve an effect similar to the one below. Note that in this definition all the circles have to be a uniform size. That's because the SphereCollide component is optimized for that condition.
Pavilion made of cardboard hoops by students at ETH, Zurich, Switzerland

Here's the definition. Download Here.

Here's the same surface with 120 circle:

Here's a sample surface with 1000 circles:

You can add a few components to get a 3D effect. First each circle is offset using the Offset Curve component. The extrusion process is achieved by using the Weave component to create a list with a circle followed by its offset. So the list is doubled in length. But it runs in pairs of circles. The next component is Partition. That breaks up the list into a tree - where each branch contains a pair of inner and outer circles. Then Boundary Surface is used make a surface for these which contains the hole in the center. This is then Extruded along the normal of each circle pair. The Amplitude component lets you set the thickness.

Planarize Hexagons

This definition will take a surface, panel it with hexagonal cells, and attempt to planarize each cell. The process of taking a surface, paneling it and making it ready for fabrication is called rationalizaion. One of the nicest methods is to planarize the panels. They can then be easily manufactured from sheet goods (for example plywood).

Here's an example that used planar panels and robotic fabrication for the edge joints.

Landesgartenschau Exhibition Hall / ICD/ITKE/IIGS University of Stuttgart

Here's the entire definition. Download Here.

This definition relies on LunchBox for the initial hexagon paneling. It generates a flat list of hex cells.

The next section gets things ready for planar paneling solving. The Explode component breaks each cell into individual segments. The output is a tree. The End Points component output start or end points of each segment. In this case we are only worried about the start points.

The key goals used are:
  • CoPlanar: Pulls a set of points towards their best fit plane. This can act on any number of points. 
  • ClampLength: Keeps the distance between 2 points between the specified limits, but applies no force when the distance is within these limits.  
The start points are wired into the CoPlanar goal. 

We need to limit the amount the segments are allowed to move. This keeps the segments all reasonably sized relative to one another. This is done by using the Curve Length and Average components to generate the average length. These are divided by constants 0.4 and 2.0 to set lower and upper length limits. 

If the Kangaroo Solver is able to solve the system it outputs the planarized curves. The Boundary Surface component is then used to surface these polygons. The Is Planar component is used to check if the surfaces are indeed planar. It outputs True for all the surfaces which are; otherwise False.

It's important to note that not all surfaces cannot be paneled with planar cells - it simply doesn't work geometrically. But this definition is remarkably successful.

When the surface is anticlastic (as indicated by negative Guassian curvature using the CurvatureAnalysis command in Rhino) the hexagons will look more like bowties as seen above and shown below:

In this example the surface is entirely synclastic and all internal panels are hexagons - although some have very shallow angles and are nearly rectilinear.

General Links to Forums and Component Code

Here's the main discussion forum for Kangaroo topics. This is a great source to find the latest definitions posted by Daniel Piker.

Here are some videos by Daniel Piker using Kangaroo:

Here's the source for additional examples: