Because 3D printers are so mainstream these days…

By Fernando Apesteguía
Project manager at OpenSistemas

…we are going to build a very humble 3D scanner 🙂

But before you read any further, here are some things you should know:

  • This is just a proof of concept. Don’t expect anything near production quality.
  • All the software used for this pet project is Open Source.
  • Some of the materials are inexpensive (a.k.a a little crappy)
  • Now that you are warned about what this post is about, let’s begin.

First off, this is a list of the things I used to build the scanner:

  • Wires
  • Some tape
  • Double-sided tape

The general idea behind the scanner is this: we will build a small square platform to place the object we want to scan. This platform will turn by one of the stepper motors. On one side, we will build a small wall with a couple of rails. We will place the distance sensor in between these rails and we will use some tether to lift the sensor when necessary. Of course, this is just a simple design. You can always choose the opposite philosophy: sit the object still and make the sensor spin around it.

This is a picture of the scanner with some of the interesting points highlighted:

scanner1

In my code, I perform 64 steps for every 360º turn, meaning I take measures every 5.625º. This seems pretty good, but you can change it easily in the code. Once we have measured the whole contour, we lift the sensor a little and start over. I take 15 measures every time, discard the highest and lowest (outliers) and compute the average.

How does this relate to a 3D object representation? What we are measuring is actually a point in a 3D space (with x, y and z axis) using polar coordinates. We know the z component (the height of the sensor), and the angle (we turn 5.625º each time) and r is the result (the average) of the output of the sensor.

scanner2

How do we convert from r and the angle to x and y? This is simple:

codigo1codigo2

We are not using the angle as is because the C library trigonometry functions expect radians (thanks Revi for pointing this out).

Most of the precision of this method is based on how we measure r with the sensor. Ah… the sensor… The Sharp GP2D120X is an infrared distance measurement sensor. It is pretty cheap and has a good precision, but probably not enough to scan objects with a lot of detail. Anyway, if you want to use another sensor (like a laser based one) you can reuse most of the code. Unfortunately for this sensor, the output is not linear. As you can see in the datasheet, the output follows a nice curve that we have to approximate as best as we can. In my case, the closest I could get was this: codigo3 that is based on this post.

 

Connections
This is a schematics of the whole set up:

scanner3

About the code

Things you need to make this code work:

  • A free Unix-like OS. I use FreeBSD (but Linux will do fine)
  • The avr-gcc suite to compile the code for the Arduino
  • A C compiler. I use clang.
  • glib
  • gnuplot

There are two separate software components in this project:

  • One for the Arduino: it takes care of measuring and turning the platform and lifting the sensor too. It also sends the data to the computer via the USB cable.
  • The compositor: it converts the readings from the Arduino to cartesian coordinates, uses the curve to interpolate and sends them to gnuplot to show them in the monitor.

The Arduino’s code is pure C with some avr-libc stuff. Why is it C and not Processing? Well… Processing is good for prototyping, but honestly, with C you know what you are actually doing when you set a pin as input, for example. The problem with this approach (it isn’t a problem actually) is that you must read the datasheet for the Atmel microcontroller.

A third-party program is necessary to plot the coordinates in the screen. I evaluated several options, like Wings3d, blender, cloudcompare, Google sketchup, jsc3d… Then I realized that there is a very well-known software that could do the job just fine: gnuplot. It is a really good program and you can pipe commands to it so it is really easy to interact with it (see gnuplot_bridge.[ch] for the details). A 3D model program would provide shadows that make the object more easy to recognize, but most of them don’t accept commands from the standard input.

The code for the Arduino has the following files:

  • common.h has a definition needed by the avr includes
  • infrared.[ch] does the same to interact with the infrared sensor
  • scanner3d.c is the main program
  • serial.h does some avr-libc magic to use printf with the serial port
  • stepper.[ch] contains the code to interact with the stepper motors
  • 3d_limits.h contains all the constants used during the run (max height, number of IR reads…)

The second part of the software (the compositor) is a small piece of software written in C + GLib. I really like the way GLib handles IO with the IOChannels. It makes everything really easy. These are the relevant files:

  • data_writer.[ch] well… yes, it writes to disk 🙂
  • channels.[ch] implements the callbacks for the IOChannels
  • compositor3d.c is the main file
  • gnuplot_bridge.[ch] implements the communication with gnuplot

 

Compiling and running the code

You can download the code from here. These steps will help you compiling and running the code:

Unpack the software:

$ tar xvzf scanner3d-0.1.tar.gz

Enter the directory

$ cd scanner3d-0.1

and type

$ make

to compile the software and

$ avrdude -V -F -c stk500v1 -p m168 -b 19200 -P /dev/cuaU0 -U flash:w:scanner3d.hex

to load it to the Arduino. Note that the MCU part (flag -p) and the programmer id (flag -c) might change if you use another Arduino board. The device file might change too. Once the program is loaded, it waits about 5 seconds before it starts the scan. This operation accesses the usb port so you will need the proper permissions for that.

Unpack the compositor:

$ tar xvzf compositor3d-0.1.tar.gz

Enter the directory

$ cd compositor3d-0.1

and bootstrap the software

$ ./bootstrap.sh

The line above will generate the necessary files and will compile the software. If you want to use a specific compiler (as clang for instance), re-run configure like this:

$ CC=clang ./configure

and then type

$ make

To run the compositor, type the following

$ ./compositor3d /dev/cuaU0

And substitute the device file by whatever applies to your system. You will need the proper permissions for this too.

 

The test

These are a couple of videos that show a teapot (the lorem ipsum of 3d objects as a friend of mine told me) and a foam tux toy.

teapot

penguin

 

Conclusions

It was pretty fun to work in this pet project. If you want to try it yourself, please feel free to use and change the code as long as you respect the license (Simplified BSD License).

Last, here you have some notes that can be of interest:

  • Use the best sensor you can get. The Sharp one is not bad for a small project like this one.
  • I am not specially gifted in handcrafting: the rotating base moves a little, the sensor inclines to one side due to the tension of the wires, etc. All these factors affect the quality of the scanning.
  • The motors I used are pretty good and cheap.
  • If you want to make your reads usable by other programs, use a standard format.
  • The capacitor between Vcc and GND improves the reads from the sensor. It should be a must in your schematics.

Enjoy!