3D digitizer

For a long time I wanted to make a device that allowed non-digital people to enter physical measurements for digital production. While using some cheap quadrature encoders for a servo control system I realized that these encoders are useful for measuring angles. At first I thought about building a structure with a X,Y- and Z axis, much like a 3D printer with the stepper motors replaced with these encoders. By moving the “print head” to different locations and reading the position of the encoders the X,Y and Z position of the head could be resolved.

Realizing that this Cartesian approach would be quite complicated to build I sought after a simpler solution.  I found that if I used the encoders as both sensors and structural bearings in a polar construction I could end up with a much simpler construction:

Build this proof of concept prototype:

Digitizer proof of concept prototype

The measurement arm has three articulated joints. Each joint consists of an encoder in turn connected to an Arduino. The respective angles of each encoder can be read by the Arduino. The base table of the system also has a turntable with its own encoder.

From encoders to angles

A quadrature encoder outputs two signals. Depending on the resolution of the encoder each signal (channel) will output a number of impulses per revolution of the encoder shaft. The phase relationship of the two signals allow an external circuitry (an Arduino in this case) to determine the direction of rotation. By combining the direction and number of pulses it can be determined how far the encoder shaft has turned. An quadrature encoder can be thought of as a reverse stepper motor.

The encoders I used emits 1200 pulses per revolution. After combining the two channels  a total of 2400 states represents a full 360 degrees rotation. The position of the encoder shaft can be represented as the number of state changes since you started counting. The numbers are counted up for one direction of rotation and down for the other, so e.g. a count of 2400 represent exactly one rotation in the positive direction and e.g. -1200 represent exactly half a rotation in the negative direction:

radians_change_since_start = counter_value * PI *2/ 2400


degrees_change_since_start = counter_value * 360 / 2400

Calculating X,Y,Z position from angles

To resolve the X,Y and Z position of the measurement tip from the encoder angles I started by calculating the height ‘Z’ of the tip above the measurement table and the distance from the center axis of the base encoder and a point right under the tip ‘r’:

Given the angles ‘E1’ and ‘E2’  , ‘r’ can be calculated as:

r =  ARM1 * COS(E1)  + ARM2 * COS( E1+E2)

And Z can be calculated as :

Z = H0 + ARM1 * SIN(E1) + ARM2 * SIN(E1+E2)

Where H0 is the height from the table top to the center axis of the E1 encoder and ‘ARM1’, ‘ARM2’ is the length of the arms. Note: H0 is also refered to as  Z_OFFSET, more about offsets later.

To find the ‘X’,’Y’ position of the tip the angle of the base encoder ‘E0’ and the value ‘r’ calculated above is used:

X = r * COS( E0 )

Y = r * SIN( E0 )

This gives the coordinetes X,Y,Z where 0,0,0 is on the table and in the center of the base encoder E0. To move the origin of coordinates to the center of the table we simply add the offset we want.

The units of the X,Y and Z coordinates are the same as the units used for arm lengths and H0. Being European I use millimeters but any unit of length may be used. My ARM1 and ARM2 lengths are the same but different lengths works as well.

Where to start

Since the encoders only record changes in angles some sort of start condition need to be set, otherwise the actual real-world coordinates can not be found. Normally some sort of end switch would be used to determine a ‘zero position’ for each encoder, much like the stepper motors in e.g. a 3D printer or CNC machine. I wanted to avoid the complexity of extra switches so I instead chose to place the measurement at a mechanically defined position and then use that as a reference. In this way all encoders can be set to an initial position at the same time.

I used a mechanical drawing of the digitizer to determine the position of each encoder with the tip at the center of the measurement table:

Knowing each initial angle the counter values for the encoders can be re-set to this position:

Encoder position = preset_angle / 360 * states_per_revolution


Since I’m working with ratios it doesn’t matter if I use degrees or radians.

Origin of coordinates

It is convenient to have the origin of the coordinates at a different position than the intersection of E0 and E1 axis. To relocate the origin to a different position I simply add some offset values to all coordinates.

Directions of rotation

The sign of the encoders needs to be correct for the math to work:

Turning the encoders in the direction of the green arrows should produce a positive value and visa-versa. Luckily the direction (sign) is easily changed by swapping the two signal wires.

These are the connections I used in the prototype:

The encoders I got need a 12-24V power supply so I connected them to Vin of the Arduino and applied an external 12V adaptor.

Build it yourself

Here is a link to the project files












Leave a Reply