Saturday, May 24, 2014

A French version! RPi Laser engraver

Fran├žois translated the RPi laser engraver post into French! Thank you Fran├žois.

Find the French version in his great website:

Saturday, March 22, 2014

A simple temperature control system (for 3D print or other constant temperature control purpose) [last update: Mar 22, 2014]

[Note: if you are using smartphone or portable device to browser this post, some math formula might not appear properly. To see the math in correct form, scroll down to the bottom and click "View web version"]
After finishing the mini CNC laser engraver, the next thing in my mind is 3D printer. One of the most important part of a 3D printer is the plastic filament extruder, composed by a cold end constantly supplying plastic filament, and a hot end melting the plastic and feeding the liquid plastic through a small nozzle.

For PLA or ABS plastic filaments (most common materials used in home-made 3D printers), the hot end needs to be at a temperature of about 200C (or 180C for PLA, 220C for ABS). It is important to keep this temperature (roughly) constant, so is the plastic melting speed and then a controllable plastic feeding rate.

Therefore two components are essential: a heater, and a temperature sensor. The heater heats up the hot end nozzle, and the sensor monitors the temperature. The heater is on when the nozzle temperature is too low, and is switched off when the nozzle is too hot.

I plan to build a home-made 3D printer controlled by my Raspberry Pi, which, unfortunately, does not have any analog data acquisition pin. Therefore I decide to build a stand-alone temperature control system.

The idea is very simple. I use a power resistor as the heater and a thermistor as the temperature sensor. The system contains an LM324 quad op-amps chip. One op-amp is used as a comparator to compare the thermistor resistance with a nominal resistance and output LOW or HIGH as the comparison result. The other three op-amps inside the LM324 are used to perform some linear transformation and output a voltage that is proportional to the thermistor temperature. This voltage is applied to a 0-30V voltmeter so one can read the temperature. A N-Channel MOSFET transistor is used to control on/off of the heater.

This is the controller
The finished controller box. About 8cm by 5cm by 4cm

Here is the circuit diagram and some key parts used in the system.

Schematics of the temperature control system

LM324 is 14-pin integrated circuit (IC) containing four identical low-profile low-power operational amplifiers (op-amp). The op-amps have a bandwidth of 1MHz, and can be powered by a single power supply with a wide range 3-32V. It is one of the most widely used and lowest cost op-amp ICs. The datasheet can be found here
[Note: there is nothing too special about this chip except its compact size. It can be certainly replaced by essentially any other type of op-amps. For the task carried by pin 1, 2 and 3 of LM324 shown in the schematics above, a comparator, instead of an op-amp, is more suitable than LM324.]

12V 40W ceramic cartridge heater resistor I used. It is the R_hot in the schematics. They are sold on ebay an other place at a price of about $2/each. For example, here
100k ohm NTC 3950 1% thermistor with glass enclosure. It is the R_T in the schematics. They have a wide temperature range from -50C to 260C. Perfect for 3D print (200C). The They cost about $1/each. E.g., here
0-30V digital voltmeter. The red lead is for power, black lead for ground, and the blue lead goes to the voltage to be measured. They are about $1.5 each (like this one). Make sure the meter has three wires. There are meters with only two wires (no blue wire) which are not suitable here.

IRFP150 N Channel MOSFET transistor. About $1.5/each (like this one). From left to right are the pins of G, D and S. Data sheet can be downloaded here. It can be replaced by similar high power N MOSFET transistors like IRFP140 or IRFZ24

Choice of the resistors

The choice for the resistors R0, R1, R2, R3 and R4 are crucial. They need to be carefully calculated so that the meter can show correct temperature.

I choose:
R0=600 ohm
R1=10k ohm
R2=3.9k ohm
R3=6.19k ohm
R4=2.4k ohm
R5=10k ohm

I will show how these numbers come out.

About the thermistor

The NTC thermistor I use has a beta value of 3950 and resistance of 100k ohm at room temperature (~25C, or rounghly 300Kelvin).

NTC stands for Negative Temperature Coefficient, meaning that the resistance of the thermistor decreases as the temperature increases.

The Steinhart Hart equation for NTC thermistor is
 where \(T_0\) is room temperature in Kelvin (~300), B=3950 is the coefficient, \(R_0\) is the resistance of the thermistor in ohm at room temperature, i.e., 100000. Then given temperature \(T\) in Kelvin we can calculate the resistance of the thermistor, or given a resistance we can calculate the temperature.

The S-H equation is a highly non-linear equation. It is, however, possible to use a simple linear function to approximate the S-H equation within some narrow temperature range.

How the temperature meter works

The system has two modes: normal working mode, and temperature setting mode. The switch SW controls which mode is selected. When SW is at 1 (default), the system is at normal working mode. When SW is at 2 (temporal), the system allows you to set the desired temperature.

The LM324 has four op-amps.Pin 4 and 11 are the Vcc and Vee. I use a single 12V power supply to power the whole system so pin 4 is connected to +12V and 11 is connected to ground. Pin [1,2,3], [5,6,7],[8,9,10] and [12,13,14] are the four op-amps.

Op-amp [1,2,3] is used as a voltage comparator. I will discuss this later.
 (It is usually not recommended to use an op-amp as a comparator. But it does work here because LM324 accepts true differential input signals into its inverting and non-inverting inputs).

Op-amp [5,6,7] behaves simply as a voltage follower. Pin 6 and 7 repeats whatever voltage Pin 5 has without draining current from pin 5. In normal working mode (SW at 1), the voltage of Pin 5 is the voltage between the thermistor and R0. We define this voltage, the voltage of the junction of thermistor R_T and R0, as \(Vin\).

With R0, there is 
$$Vin=\frac{R0}{R0+R_T}12  V=Pin5=Pin6=Pin7$$

Then let's move to resistor R1 and R2. Clearly, the voltage at pin 10 is
$$ \frac{R2}{R1+R2}\cdot12+\frac{R1}{R1+R2}\cdot Vin=\frac{R1}{R1+R2}\left(\frac{R2}{R1}\cdot12+Vin\right) $$

Op-amp [8, 9, 10] is another voltage follower. Hence Voltage of Pin 8 = Pin 9 = Pin 10.

Resistor R3 and R4 form a voltage divider. The voltage between R3 and R4 is
$$\frac{R4}{R3+R4}\cdot Pin9=\frac{R4}{R3+R4}\frac{R1}{R1+R2}\left(\frac{R2}{R1}\cdot 12+Vin\right)$$
Op-amp [12,13,14] is another follower. There is Pin 14=Pin 13 = Pin 12= voltage between R3 and R4.

We define the voltage at Pin 14 is \(Vout\). Hence
$$Vout=\frac{R4}{R3+R4}\frac{R1}{R1+R2}\left(\frac{R2}{R1}\cdot 12 + Vin \right) $$

Now plug into the numbers: R1=10K ohm, R2=3.9k ohm, R3=6.19k ohm, R4=2.4k ohm, we get
$$Vout=0.279\times 0.719\times (0.39\times 12+Vin)=0.2(4.7+Vin) $$

All the three op-amps do is to perform this linear scaling.

Here is the magic. I claim that, with R0=600ohm and \(Vin=600/(600+R_T)\times12\)V, there is
where T is the temperature of the thermistor in Celsius. This equation is true for a quite wide temperature range 120C-260C.

The figure below is the proof. It is shown that with R0=600ohm, \(Vin\) is quite linear in the range of 120C to 260C. Therefore we can perform some linear transformation to map \(Vin\) linearly to T/100.

Top left: thermistor resistance at different temperature. Top right: same as top left but with axes switched. Lower left: with R0=600ohm, Vin as function of temperature from 90C to 280C. Lower right: Vout as function of Temperature (blue) and T/100 (red, T in Celsius)

To map Vin to T/100, we perform linear regression between Vin and T/100, and obtain

Recall that
$$Vout=\frac{R4}{R3+R4}\frac{R1}{R1+R2}\left(\frac{R2}{R1}\cdot 12 + Vin \right) $$
If we want to have \(T/100=Vout\), there must be

Since \(R2/R1=0.39\) gives \(R1/(R1+R2)=0.719\), the second requirement is reduced to

Therefore [R1=10K ohm, R2=3.9k ohm, R3=6.19k ohm, R4=2.4k ohm] is an obvious solution (not the only one though).

Here is a list for key parameters at different temperatures

   T(C)    R_T(k ohm)     Vin (V)      Vout (V)          

  120          4.0594          1.5453        1.2491
  140          2.4950          2.3263        1.4053
  160          1.6041          3.2667        1.5933
  180          1.0723          4.3055        1.8011
  200          0.7416          5.3666        2.0133
  220          0.5285          6.3801        2.2160
  240          0.3867          7.2969        2.3994
  260          0.2897          8.0928        2.5586

Note that the \(Vout=T/100\) relation is preserved very good within the range of 140C to 240C. Detailed calculation shows that the averaged errors from 140C to 240C is less than 0.5%. Very good!

We feed this Vout to a voltmeter so the voltmeter reading is T/100.

How the temperature control works

The temperature control is done by the op-amp [1,2,3]. Toggle the SW to position 2. The meter is reading a temperature assuming the potentiometer R is R_T and R0. We set the potentiometer R so that the meter reads the desired value, say 2V (corresponding to 200C). Then toggle the SW back to position 1.

The voltage of Pin 3 is then a constant. The voltage of Pin 2 equals to Pin 3 when and only when the temperature is 200C.

Below 200C, R_T is too large. So the Pin 2<Pin 3. The op-amp is trying to amplify the voltage difference between its non-inverting (pin 3) and inverting pins (pin 2) by hundreds of thousands times. But it can't output any voltage above the power supply voltage-1.5V Therefore it outputs 12-1.5=10.5V through pin 1. The Gate-Source voltage of the MOSFET transistor is then large enough and the D-S of the MOSFET become conductive. The heater is then switched on.

When the temperature hits above 200C, R_T is too small. So the Pin 2>Pin 3. The op-amp outputs zero at Pin 1. The MOSFET is switched off and so is the heater.

After the temperature drops below 200C again, the cycle repeats.

So it is a negative feedback system. The temperature is maintained around 200C.

Note that when Pin 1 outputs 10.5V, the LED is also switched on to indicate that the heater is working.

Some remark

The system accomplishes two major tasks: displaying the temperature correctly and maintaining a constant temperature at the location of thermistor.

The first task is accomplished by using three op-amps. The limitation is that the system can only display temperature correctly within a certain range. Here, in our case, is 120C-260C. Below 120C or above 260C the system behaves very poor.

Mathematically it is guaranteed that the op-amps idea will definitely work essentially for any system, but within some limited range. This is because in most times the Taylor-expansion of any smooth function \(f(x)=f(x_0)+(x-x_0)f'(x_0)+...\) always has a linear term \((x-x_0)f'(x_0)\). One can always use a linear function to approximate the real function. On the other hand, this approximation only works within a narrow range.

I feel very lucky that the linear range in my case is so wide (120C-260C).

To properly display the temperature in wider range, say, 0C to 300C, it is necessary to use some micro controller to perform the complicated T-R conversion calculation. But micro controller is is far more complicated and expensive than LM324.

My idea can be easily extended to other system. For example, a constant temperature water-filling container (what does it for? Say, 45C Baby milk warmer). One need to linearize the system around 45C and find proper R0-R4.

A note is that LM324 can no output voltage below 0 or above (power supply voltage-1.5V). So every step of the linearization shouldn't involve any voltage beyond this range.

I will upload more pictures and maybe a video showing how the system works.

Thursday, February 27, 2014


Ian Miller, a high school senior in Manhatten, Kansas, built his own version of the Pi-Powered Laser Engraver: engravR. Besides the great YouTube video, he also wrote an excellent tutorial on Makezine.

In the tutorial, Ian included a great circuit schematics of the entire system, which I didn't have in my post. So everyone trying to make a similar project is strongly recommended to visit his tutorial and his blog pxlweavr. He used different H-bridge drivers I believe.

My writeup is here

Saturday, February 8, 2014

A simple analog proximity sensor with digital interface (for Raspberry Pi) [last update: Feb 7, 2014]

[Note: if you are using smartphone or portable device to browser this post, some math formula might not appear properly. To see the math in correct form, scroll down to the bottom and click "View web version"]

Raspberry Pi has a Broadcom BCM2835 chip, which controls 26 GPIO (general purpose input/output) pins. There are C library or RPi.GPIO python package available online that can be used to control the pins. The RPi.GPIO package is by default included in most Raspberry Pi system, such as Raspbian, a RPi version of Debian linux system.

One drawback of RPi, compared to arduino, is that it doesn't have any analog pin. All the GPIO pins are purely digital. For example, if pin A is an output pin, it can only output LOW (0V) or HIGH (3.3V), represented as 0 or 1. If pin A is an input pin, for any voltage below 0.8V applied on pin A, it takes it as LOW or 0; for any voltage above 1.3V (surprisingly low actually!), it takes it as HIGH or 1 [ref: RPi GPIO].

In real world, however, purely 0 or 1 rarely happens. We always get information that can have continuous value in its range. For example, temperature can be 10C or 50F, or 100C or 212F. These number contains more information than simply "cold" or "hot". A distance can be 2 cm or 10 m, and it is not enough to only know "close" or "far away".

There are some methods to overcome this drawback. RPi does support SPI or I2C interface, so that we can use some external analog to digital converter (ADC) and use SPI or I2C interface to get quasi-analog signal through these ADCs, such as MCP3008, TLC549, MCP23017, etc. These chips usually cost several bucks. However, with additional commercial sensors, the whole part can cost more than $20 to $30, and it is difficult to make the system compact. For robotic project one usually need more than one sensor, and the cost can add up easily.

In fact, in many situations, it is actually possible to avoid using these external devices, and still able to get analog signals through the digital pins!

The key is to convert analog signal to time duration. Because time is always analog!

I build a simple infrared proximity sensor using several infrared LEDs, one phototransistor, one 2N3904 NPN transistor, a 100nF ceramic capacitor and several low power resistors. And I am able to get some analog reading.

Here is the circuit.
Infrared Proximity Sensor
All the elements are among the cheapest in the electronic market.

It doesn't really matter what LEDs, phototransistor or NPN transistors are being used. They are pretty much the same.

The only thing that might matter a little bit is the 100nF (0.1uF) capacitor. I used a low profile ceramic one, which is probably not the best choice. A class 1 ceramic, or film capacitor, will be more suitable here.

Here is the real image of the sensor.
The infrared proximity sensor. The phototransistor is protected by a black rubber cylinder and surrounded by four infrared LEDs. You can also find the ceramic capacitor (upper left) and two resistors. A third one is on the other side. The sensor has four wires, +5V, GND, Trigger and OUT. The whole sensor is about 1.5cm by 2cm.

Connect the +5V and GND wires to an external 5V power supply, also connect the GND wire to the ground of the Raspberry Pi GPIO pins. Choose one GPIO pin, say, Pin A as the trigger and connect it to the Trigger wire. Choose another GPIO pin, say, Pin B, as the signal input/output and connect it to the OUT wire.

To measure the distance of an object, we send a trigger signal to activate the infrared LEDs. The light emitted by these LEDs are then reflected by the object in front of the sensor. The phototransistor in the middle collects the reflected light and generates a proportional current. This current is used to integrate the voltage across the capacitor (I=CdV/dt). By monitoring the time it takes the capacitor voltage to reach some certain threshold, we have a sense of how much current was generated by the phototransistor, or equivalently, how much light got reflected. Apparently, closer the object is, more the reflected light is. By carefully calibrating the timing of the sensor, we should be able to get a pretty precise measurement of the distance.

Here is the detailed sequential of operations.

1. Zero the capacitor

First set Pin B to be an output pin and set it to be zero.



 This will discharge any residual voltage on the capacitor. Note that the RC time for discharging the capacitor is t=RC=500ohm * 100nF = 50 us = 0.00005 sec. By maintaining zero volt at pin B for 200RC time, we make sure the capacitor is fully discharged (the residual voltage should be \(e^{-200}=10^{-87}\) times the original residual voltage).

2. Set Pin B as Input

Now we use Pin B as an input pin to get data from the phototransisto.


3. Light up the LEDs

It's time to turn on the infrared LEDs.


This will set the voltage of trigger pin to be 3.3V. Since the BE node of 2N3904 drops 0.7V, the voltage across R1 is 2.6V. The current through R1 is then \(I=2.6V/4.3k \Omega=0.6 mA\). 2N3904 then amplifiers this current by ~150 times, resulting a ~ 100mA current from its collector to emitter. Each of the LEDs will conduct about 50mA for a short time period.

4. Timing the duration of Pin B remaining LOW

Start to measure how long it takes the capacitor to reach RPi's threshold so Pin B becomes HIGH

        counter = counter+1

deltat is the time duration of Pin B remaining LOW. Since deltat is proportional to the reciprocal of phototransistor current (or amount of reflected light), and phototransistor current is roughly proportional to the reciprocal of the distance, deltat is roughly proportional to the distance.

deltat\(\propto \frac{1}{I}\propto \frac{1}{light}\propto distance\)

The (counter<1e4) term is to prevent the situation that it takes too long to integrate the capacitor due to extremely low phototransistor current, or equivalently, infinite distance.

5. Turn off the LEDs


Before using the sensor practically, we can calibrate the sensor by establishing a table of 1-to-1 correspondence of deltat and distance. When using it, after getting deltat, we just need to check the 1-to-1 table obtained during the calibration.

Now there is a clear flaw of the sensor. The amount of reflected light is not only affected by the distance, but also affected by the reflectivity of the object. A shinny mirror will definitely reflect more light compare to a sponge. I don't know if there is a simple solution to this issue. If we know what object the sensor might encounter, we can use that object to calibrate the sensor.


What's the speed of the sensor? It has something to do with the distance of the object, and the capacitance of C. A shorter distance or smaller C will give a faster measurement speed. I did some test with the configuration shown in the circuit above, it generally takes no more than 0.05 sec to measure distance from 0 to 10 cm (4in).

Minimize the affect of ambient light

Another potential issue is the ambient light. If the ambient light is too strong, it will interference with the LED light and result in an unexpected large phototransistor current, and a shorter deltat. The sensor might think it is getting too close to an object, but in fact it is facing some bright light source.

If the ambient light is fast varying, there isn't too much we can do about it, unfortunately. However, if the ambient light level remains roughly constant when measuring the distance, there is a simple solution to this issue. Since it takes about 0.05 sec to measure a distance, this requires the ambient light stays constant during this time period. Good enough for most everyday usage.

We can first perform the above steps and get a deltat , denoted as \(\delta t_1\). Then keep the LEDs off, and redo step 1, 2, 4 to get a second deltat , denoted as  \(\delta t_2\).

\(\delta t_2\) is the time duration it takes the ambient light to charge the capacitor.  \(\delta t_1\) is the time duration it takes both the ambient light and LED light to charge the capacitor.

Since (1/deltat\(\propto light\)), we need to compute

$$\delta t \equiv \frac{1}{1/\delta t_1-1/\delta t_2}=\frac{\delta t_1\delta t_2}{\delta t_2-\delta t_1}$$

The ambient light effect is then removed.

Or we can use pulse-width-modulation (PWM) to precisely control the amount the light emitted by the LEDs, and measure deltat several times with different LED brightness, and then perform a linear regression to get the true deltat given by pure LED light.

For example, set the LED power to be 0% (off), 25% (0.25 on duty during each PWM duty cycle), 50%, 75%, 100% (solid on), and get the corresponding  \(\delta t_1, \delta t_2, \delta t_3, \delta t_4, \delta t_5\)

Denote \(P\) to be the power of LED, \(P=0, 0.25, 0.5, 0.75, 1\).

If both the distance and ambient light remain constant, there should be

$$\frac{1}{\delta t}=\alpha P+\beta$$

\(\frac{1}{\delta t}\) is proportional to the total light collected by the phototransistor. \(P\) is proportional to the light emitted by the LEDs, \(\beta\) is the effect of constant ambient light.

Obviously, coeffcient \(\alpha\) is determined purely by the distance. In fact, \(\frac{1}{\alpha}\) is the true deltat without any ambient light. Roughly speaking, \(\alpha\) is proportional to 1/distance.

We perform a linear regression to \((P_i, 1/\delta t_i)\), where \(i=1,2,3,4,5\). The best fit coefficient \(\alpha\) is given by

$$ \alpha \equiv \frac{<P_i/\delta t_i>-<P_i><1/\delta t_i>}{<P_i^2>-<P_i>^2} $$

where \(<x_i>\equiv\sum(x_i)/N\) is the mean of all \(x_i\).

Other thought

I got this idea from this post

Reading analog values from Digital Pins of Raspberry Pi

The idea of converting analog signal to time duration is very neat. The original post claims

The above technique will only work with sensors that act like resistors like photocells, thermistors, flex sensors, force-sensitive resistors, etc.

It cannot be used with sensors that have a pure analog output like IR distance sensors or analog accelerometers.


However we show that it is actually doable with devices like photodiode or so.

I am  putting the python codes into a mature package now. I will keep updating this post and include the package.

Sunday, October 20, 2013

A Raspberry Pi controlled mini CNC Laser engraver [last update Jan 18,2014]

I recently made a mini CNC laser engraver using two DVD drives salvaged from old computers and <$10 extra parts bought on eBay. The controller of the CNC machine is a Raspberry Pi, a $35 credit card size computer. The engraver turns out to be pretty successful. So I am sharing it with everyone.

There have been a lot of examples people using Arduino to control CNCs. You can probably find tons of C programs available that run directly on Arduino to process G code. A famous one is grbl. Like this on by Groover in instructable A Chinese translation can be found here. Also there are available CNC controller like MATH3 on the market that can be controlled by parallel or serial ports.

I am taking a different approach by using a RPi (
A Raspberry Pi mini computer. Raspberry Pi is a trademark of Raspberry Pi Foundation
The reason why I choose Raspberry Pi is: it is a much more powerful device than Arduino; it supports complete OS; the GPIO pins can be controlled by python, a more intuitive and simpler language than C (the disadvantage of python would be the slow speed); I don't have to buy a separate controller for this project--I can use a single Raspberry Pi to do a lot of different things without reloading firmware. Most importantly, I have a Raspberry Pi but don't have an Arduino right now!

Also, there are projects people running LinuxCNC on Raspberry Pi and use an external PIC 32 board to control CNC. It's a great idea but I want to minimize the cost. Instead, I wrote my own python interpreter to execute G code directly. For 2D CNC laser engraver, it is actually very easy to control and doesn' require too much program techniques.

First, some pictures.
Laser engraver is working

A coin size university icon on a plastic board

I messed up the direction for this one...

Some words..

The machine is not packaged yet. You can find: machine (top middle), controlling circuit (top left) and RPi (lower right)
The controller and wires in a perfect chaos

Other version
D. Miller made his own version of laser engraver and posted a fabulous youtube video here

Please visit his website pxlweavr

He made a couple of great improvements to my python codes, so that it is able to use G Code generated by the inkscape GCodeTools extension, and also allows remote engraving via another small python script he wrote. The modified python package can by obtained from github
 Must read!!!
As everyone does, I feel crazy about laser. But it is extremely important to keep in mind that the laser used in this project could burn human eye retina in millisec before eyeball is capable to react. Even a random reflection beam during engraving could be >50 mW (for comparison, a regular laser pointer is 1 mW), and make permanent damage to your eyes, kids' eyes, or pets' eyes. ALWAYS WARE A LASER SAFE GOGGLES when you are close to the working engraver. A suitable one for 650 nm laser should be green color. MAKE SURE THE ENGRAVER IS NOT ACCESSIBLE TO KIDS OR PETS. I would suggest everyone planning to build this should enclose the whole thing inside a large box or cover (however, mounting a little computer fan on the box would be nice for venting). Some people suggest that there should be a master switch on the box, so that unless the box is closed, the laser won't switch on.

AGAIN, think TWICE before you make it.

About the capability of the engraver

Due to the size limit of DVD drives, the machine can only engrave within an area of 36 mm by 36 mm.. So it can do little pieces of wood, plastic board or part of  iPhone cases, but not any larger.

The laser used here is 200 mW 650 mm red laser diode. It cuts letter paper fine. But It is not powerful enough to actually cut through anything thicker and tougher. In fact, the working surface is preferred to be black color so that it can absorb as much laser power as possible. To engrave on transparent plastic board, as shown above in the coin size university icon picture, I have to use a black marker to paint the surface and clean the ink after engraving. However, I believe for a thin black foam sheet (<3mm thick), and given enough engraving time, the laser should be able to cut it through, as Groover showed in instructable.

Now here is the instruction.

Things required:

1. A raspberry pi (running Raspbian or what ever supports GPIO)

2. two DVD writable drives.
To be able to engrave, you need 200mW laser diode from DVD writer. A DVD R or CD R will do nothing. A CD writer might be OK in term of power (~100mW), but the laser diode of a CD writer is infrared, which can be super dangerous (you can't see it!).

3. a TO-18 5.6mm laser housing
(like this one
Make sure you get a 5.6mm one. There is another type 9mm.

4. Two dual channel H-bridges.

A H bridge is a circuit containing four (effective) switches that can apply a voltage across a load (DC motor or one coil of a stepper motor) in either direction.

Stepper motors from DVDs are 4 wire 2 phase bipolar stepper motors. They require truly reversible voltage on each pairs of the wire. You need two H bridges for each stepper motors. So total of four H bridges for two strepper motors. Some famous stepper motor controllers like ULN2003 are for the 5 wire stepper motors, so they cannot be used for controlling the DVD stepper motors.

You can make your own H bridges by using 4 NPN and 4 PNP transistors and probably TTL converters (RPi's GPIO pin are 3.3V so logic TTL chips might be required). Or you can simply buy them. There are a lot of integrated H bridge circuits available in the market, such as L298. The ones I use are L9110s Dual H Bridge purchased on Ebay (like this one: They are low cost (~$2 each), compact (.8"x1") and are powerful enough (~800mA). However, if you buy from a Chinese seller, shipping can cost 3 weeks.

L9110s is also known as HG7881.

Regarding the H bridge, you need to make sure that the continuous current limit of the circuit is greater than 500mA. Usually the stepper motor in a DVD drive is rated at 5V and each coil has a resistance of 10ohm. So the current through each coil would be 500mA! A very large current!

5. a LM317 regulator, a power NPN bipolar transistor (like E3055, should be able to handle continuous 200mA at least), some resistors, capacitors and a bundle of jumpers.
The LM317 is for the laser driver. The power NPN is for making a switch for the laser. My lab has tons of these components so I don't have buy them. If you don't want to solder a driver by your own, you can surely buy a laser driver for <$5. The laser driver need to be able to output at least 200mA at 2V and have the function of enable/disable.

If fact, it might be a better idea replacing the NPN bipolar with a MOSFET transistor. There are a lot of them available on the market and are very inexpensive. Just make sure that the continuous current supported by the MOSFET is above 200mA.
6. a solder gun, screw driver and some basic hard wares.

STEP 1: Disassemble DVD drives

There are a lot of picture/video tutorials online for this step so I will keep it short.

Two DVD found in E-waste
They are rewritable

All you need from the DVD are
1. stepper motor with the slider (lower right part in 
the picture below)
tearing down a DVD

2. Laser diodes (see picture below). Be very careful
 that the laser diodes on the DVD are very fragile.
 Make sure you don't break them. 

Two 5.6mm laser diodes (infrared and 650nm red) 
compared with a USB connector.

Stepper motor (right) and linear slider. 
I soldered four wires on the stepper motor.

There are other good things you can salvage from the DVD drive and keep for future projects, such as a 9 V dc motor near the gate, a brushless motor that spins the DVDs, some shock reducers and some miniature lens and optic parts. You can also find four strong magnets near the laser diode. Don't throw them away. They will turn out to be useful later.

STEP 2: Assemble Laser

Now you have two laser diodes. One is infrared which we don't need. The other one is 650nm red diode (usually has a letter 'R' on it) and is the one we need. The diode normally has three pins forming a fat triangle. One is NC. You need a multimeter to figure out which two pins are cathode and anode. The forward voltage across anode and cathode should be around 1.4V and the forward resistance should be 20-40k ohm. If the forward resistance is too high then the laser diode is over used. 

The laser diode housing

Laser diode (middle left) and laser housing 

Pushing the diode into the housing head

Laser diode in the housing head
Solder two wires on the diode
Use some heat shrink to increase the strength

Getting there


Carefully put the laser diode into the head of the laser housing. You can use the laser housing body to help knock against the diode and push the diode into the housing head. The diode should fit perfectly into the head. Make sure the pins are still fine. Then solder two wires to the electrodes and assemble the housing together.

STEP 3: Make laser driver and enabler and test the laser

A laser diode is like a photodiode but equipped with a resonant cavity. Laser diode is a huge current sink. Once the diode conducts, it generates a lot of heat, and the heat further lowers the diode impedance. So it is a unstable positive feedback system. If you simply put a 1.5 V battery across the diode, you will either get the diode burn or battery drained right away. We need a laser driver that can output a constant current to the diode.

There are numerous way to do this. One of the most popular and least frustrating way is to use a DC current regulator. LM317 is a good choice. By adding a resister R across the adjust pin and output pin, LM317 can output a constant current of ~1.25V/R.

[In fact, LM317 is mostly used as a voltage regulator. It maintains a 1.25V across the output pin (pin 2) and the adj pin (pin 1). Meanwhile, it controls the current output from the adj pin to be very low (usually <100 uA). Therefore by adding a resistor R across pin 2 and 3, we can have 1.25V/R current output from pin 2 to pin 1. We then add the laser diode across pin 1 and GND. Since pin 1 is forbidden to sink current, all the 1.25V/R current outputted by pin 2 will flow through R and laser diode to GND. The official datasheet of LM317 can be download here .

Here is a good LM317 laser drive circuit I found here LM317 Laser Driver (this link is already expired...)

 In my case, I replace the two parallel 10 ohm resistors by two .5 Watt 12 ohm resistors. The max current I am going to run through the diode is 200mA.
Make sure you don't mess up the adjust pin and the output pin. A heat sink would be necessary on the LM317.

You also need a switch that can be controlled by RPi. I used a power NPN E3055 transistor. You can choose what every you want, just make sure that the transistor can support continuous CE current >300mA and also put a heat sink on it.
Schematics of the laser driver and the switch. Laser is on only when "Laser switch" port  is logic high (>3V). Make sure you don't mess up the pin order of LM317

LM317 Laser driver

Laser driver (top) and the E3055 power NPN (bottom)

Laser diodes are very delicate device. They are extremely vulnerable to the condition applied on them. Unstable voltage or current, excessive current/voltage (even for very very short time) could damage them permanently. So always discharge yourself before holding the diode, and always use a constant current driver to power it. As pointed out by one of the reader (thank you, J super), you might also damage the diode by connecting the driver to power supply first and then connecting the diode to the driver. The diode should always be connected to the driver before applying any power to it.


STEP 4: Shape the machine

Now you have two identical linear stages and it is time to put them together! There are a lot of ways to do this. For 2 axes CNC machine, I think the best way is the one given by Groover @ instructable. In Groover's configuration, the engraving sample is attached to x-axis so it only moves in x direction. The laser is attached to y axis so it only moves in y direction. This configuration minimizes the weight on each of the axes.

Laser engraver I made

I cut a 2"x2" steel board out of the DVD case and glued it to the x-axis stage as the sample support base. Since the DVD case is made from iron, you can use the strong magnets salvaged from the laser optical system to help you stabilize the engraving sample on the base.

The laser diode will generate a lot of heat . And it is important to dissipate this heat.  Otherwise the diode will die fast. I cut a 1inch cube heat sink from an old computer CPU heat sink and drilled a hole though it. The hole is perfectly large to hold the laser. I glue the heat sink on the y axis stages.

The most important issue is the x axis, y axis and body of laser have to be perpendicular to each other.

STEP 5: Connect H-Bridge to the stepper motors

Four connect pins on a 4-wire-2-phase stepper motor. They are usually arranged in the following order: a1,a2,b1,b2. (a1 and a2 are the two leads of coil a; b1 and b2 are the two leads of coil b). Using a multimeter will help to verify this.

The stepper motor in DVD is a 4-wire 2-phase bipolar motor. There are two independent coils inside. Each coil has a 10 Ohm resistance. Usually the DVD stepper motors are rated at 5V. Therefor the rated current through each coil is 500mA! The RPi GPIO pins can only output less than 20mA so RPi cannot control a stepper directly. H bridges are required.

Here is a very good tutorial on Bipolar stepper motor Bipolar Tutorial

Conceptual model of 4-wire 2-phase stepper motors, from Bipolar Tutorial.I renamed the pins

Seems I am using different names for pins of stepper motor. In most people's writeup I can find online, they define coil 1 and coil 2 and name 1a, 1b as the two leads of coil 1, and 2a, 2b as the two leads of coil 2. It doesn't matter, as long as we know what we are doing. At least in this post I will keep the terminology thing consistent.

The central spinner of the bipolar stepper motor can be regarded as a bar magnet (actually it is circular). Obviously from the figure above that if we successively conduct current in coil a1, b2, a2 and b1, the spinner will spin in the desired sequence. To do this, we can apply a voltage sequence to a1, b2, a2, b1 as:1) high, low, low, low. So only a1 and a2 are activated. Since a1 a2 have same polarity (or opposite depending on how you define it), the spinner is pointing to a1
2)low, high, low, low. So only b2 and b1 are activated. Spinner is pointing to b2
3)low, low, high, low. So only a2 and a2 are activated. Spinner points to a2
4)low, low, low, high. Spinner points to  b1.
go to 1).

Denote high as 1 and low as 0. The sequence can be written as 1000,0100,0010,0001

The advantage of this configuration is that it is very easy to understand and usually the stepper motor moves very precisely. However, since in each step only one pair of coils is activated, the torque applied on the spinner is not very great.

To achieve high torque, a more popular way is to apply the following sequence: 1100,0110,0011,1001. And the spinner will be pointing to middle of a1 and b2, middle of b2 and a2, middle of a2 and b1, middle of b1 and a1 consequentially. And the torque is doubled. This is called full-step mode or high torque mode or two phase mode.. and is usually the mode used.

If the torque won't be a problem then we can use a 8-step sequence: 1000,1100,0100,0110,0010,0011,0001,1001. The spinner will turn 8 steps instead of 4 steps to turn same angle. This doubles the resolution. And the cost is the non-uniform torque being applied on the stepper motor. This is called half-step mode.

Usually for DVDs, the linear sliders moves about 0.15mm every full step stepper motor turn, corresponding to a resolution of ~170dpi. Good enough for home-made projects. If 8-step mode is implemented, then the resolution is 0.075mm/step or 340dp, similar to regular printer.

For laser engraver, there isn't any serious load on the stepper motor so I choose the half-step mode or 8-step mode.

As mentioned, RPi cannot drive the stepper motor directly because of the current limit. Actually, besides powering low power LEDs, the GPIO pins of a RPi usually serves as logic switches. In output mode, they are either logical High (3V) or logic low (<0.7V). A H bridges is a "translator" that translates these logic High or Low into power source that has high voltage or low voltage.

File:H bridge.svg
A conceptual schematics of H bridge (from wiki)
Above is a conceptual schematic graph of H bridge (has similar shape with letter "H"). One H bridge has two working mode: (S1 S4 close, S2 S3 open) and (S2 S3 open, S1 S4 close). In the first mode, current flows rightwards through the motor and in the second mode, current flows leftwards through the motor. In reality, this H bridge is never used. A common way is to use transistor as electric switches. See figure below.
A very very simplified conceptual schematics of NPN PNP H bridges. NEVER build an H bridge based on this graph. You will probably burn the transistors or even the Pi. A practical H bridge requires current limiting resistors, reverse diodes and logic TTL chips. Please consult more from other sources if you would like to build a working H bridge from scratch.
When A is logic low (0V) and B is logic high(+V), then transistor 1 and 4 are conducting while 2 and 3 are open; when A is logic high (+V) and B is logic low (0V), then transistor 1 and 4 are oepn while 2 and 3 are conducting. When both A and B are logic high, 2 and 4 are conducting, 1 and 3 are open, the motor stalls; when both A and B are low, 1 and 3 are conducting, 2 and 4 are open, the motor stalls.

Therefore by setting A and B high or low, we can control the current direction through a load. For each 4 wire 2 phase stepper motor, there are two independent coils we need to control. So a total of 4 H bridges are required to control the two stepper motors.

There are a lot of integrated H bridge available on the market. For my case, I need 500mA through each H bridge so L9110S suffices (L9110S can afford 800mA through each H bridge). Each L9110S contain two H bridge so two of them is enough. There are L9110S module for <$2 each on the market. Very convenient!

I am not exactly sure but I think sometimes people call it L9110 sometimes L9110S.. Datasheet can be found here.

Also, L9110S has internal clamp diodes to conduct the reverse current generated by the sudden stop of the stepper motors. This protects the circuit. L9110S is TTL/CMOS output level compatible so it can be directly connected to RPi.

Two L9110 dual H bridges (also known as HG7881). They are 0.8" by 1" big
Each dual bridges control a stepper motors. On the right hand side, there are a1, a2, b1, b2 connectors to the stepper motors (top to bottom). On the left hand side, there are logic control pins for a1, a2, b1, b2 (actually they are named as A-IA, A-IB, B-IA, B-IB) and VCC and GND.

When powered, the chips light up (The big circular thing is my ring. I don't have a big finger..)

STEP 6: Driving the machine using Raspberry Pi

Now this is the key part. Because I am not using external stepper motor drivers so I have to incorporate the function of external stepper drivers in software. I choose python to do the job.

People say that RPi is not a real time device because it has an entire OS on it and python is very slow. However, in my case, these issues didn't cause any trouble.

The python code I wrote includes the following functions:
1. An encapsulated bipolar stepper motor class. It enclosed information like phase and position. It has a .move(direction, steps) build-in function that converts movement commands into a sequence of GPIO.output() commands that spins the stepper motors. 
2. A G code interpreter: read G code and send the corresponding commands to the bipolar stepper motor objects. For G02 and G03 commands (circular interpolation), the interpreter performs the interpolation and converts the commands into a sequence of straight motions.

The most challenging part is how to control  more than one stepper motor simultaneously. The idea is actually very simple and can be extended to any number of motors. We already know how to control one motor. Now suppose we have two motors: MX and MY, and we want to turn MX 12 steps and MY 15 steps simultaneously in 6 seconds. First find the least common multiplier (LCM) of 12 and 15, which is 60. Now divide 6 seconds by 60 we get dt=0.1sec. Set 60 loops. Before the end of each loop, we use time.sleep(0.1) commands. So it takes 6 sec to finish the loop. And we move MX one step every 5 loops and move MY one step every 4 loops. After 60 loops, MX moves 60/5=12 steps and MY moves 60/4=15 steps. And both MX and MY moved at constant speeds. 

0000100001 0000100001 0000100001 0000100001 0000100001 0000100001 (60 digits, 12 ones)
0001000100 0100010001 0001000100 0100010001 0001000100 0100010001 (60 digits, 15 ones)

For more than two stepper motors, just find the LCM of all the steps (ignore 0).

You can download all the python code here My RPi CNC Laser Engraver Code:

You can find three python codes:

Project: raspberrypi-cnc-laser-engraver

CodeUploaded byDateLanguage
Bipolar_Stepper_Motor_Class.pyXiang ZhaiOctober 25, 2013, 11:34 pmpython
Motor_control.pyXiang ZhaiOctober 25, 2013, 11:38 pmpython
Gcode_executer.pyXiang ZhaiOctober 25, 2013, 11:39 pmpython
spiral.ncXiang ZhaiNovember 11, 2013, 6:31 pmtext
grid.ncXiang ZhaiNovember 11, 2013, 6:38 pmtext defines the Bipolar_Stepper_Motor class. By default, line 5 is commented and line 7 is valid. This corresponds to a 8-step half-angle sequence. If maximum torque is desired, you can comment line 7 and uncomment line 5 to select 4-step full-angle sequence. defines a set of functions such as LCM (for calculating the lcm of two integers) and Motor_Step (for controlling two motors simultaneously). Usually you don't need to modify anything.
This is the main program. You need to modify line 25 (G code file name), line 29 (pin numbers for stepper motor X), line 31 (pin numbers for stepper motor Y), line 32 (pin number for laser switch), line 35, 36 (resolution of the machine in unit of mm/step) and line 38 (engraving speed). The code read and interpret G code, and send corresponding commands to the motor control functions.
This is a simple G code which plots a small spiral. It can perfectly test whether the machine can process G code, especially the circular interpolation G02 and G03, correctly.
A simple G code which plots several straight lines to make a grid. Perfect code to test the machine and make a coordinate system!

Currently the only accepts limited number of G commands: G90, G20, G21, M05, M03, M02, G01,  G02, G03.
The code can recognize G1F commands (engraving speed) but simply ignore it.  Engraving speed is set by line 38 in unit of mm/sec.

As mentioned at the beginning of this post, D. Miller made some improvement to my code so that the code can work along with the inkscape GCodeTools extension and allow remote engraving via another small python script he wrote. The modified version can be downloaded here

STEP 7: Engraving!

Following Groover (by Groover in instructable), I use Inkscape to make G code. Inkscape is an open-source vector graphics editor and support various OS (windows, linux, Mac), which means that you should be able to install it on Raspbian! I didn't try that. I simply use my laptop and send my design to the RPi.

You need a laser engraving extension to convert vector graph into G codes. There are several different G code extension. The one I use can be downloaded here Inkscape-Laser-Engraver-Extension

[Note: I wrote my python G code interpreter based on the G code generated by this Inkscape extension. So the code can only deal with limited numbers of G commands, sufficient for laser engraving though, fortunately. For G codes given by other generator, my codes might not be able to handle all the commands. You might have to modify the python code on your own.]

Here is the step-by-step instruction on how to generate G code that my python code can process.

Step 7-1: Install Inkscape and Inkscape-Laser-Engraver-Extension

Inkscape can be freely download here
It runs on windows, mac and various linux OS.

Then download Inkscape-Laser-Engraver-Extension here.

To install the extension, simply unzip the file and copy everything into the Inkscape installation folder. For example, in Windows 7, if Inkscape is installed under
C:\Program Files\Inkscape
, then just copy everything from Inkscape-Laser-Engraver-Extension to C:\Program Files\Inkscape\share\extensions
and then restart Inkscape, the extension should be already installed. To verify this, run Inkscape and check for "Laser Engraver" item under "Extension" on the manu bar.

The Laserengraver extension is successfully installed

Step 7-2: change page size

Open Inkscape, goes to  "File" => "Document properties" => "Page", under the "Custom Size" box, change the "Units" to "mm" (millimeter) and then put 36 and 36 in both "Width" and "Height". Then close the dialog.

You will see the blank page becomes a small square box. Zoom into that box.

Step 7-3: plot, text, create, a lot of fun~

You can type texts, plot graphs, or even paste png/bmp in the box.

Press "Ctrl" and "A" to select everything plotted, under "Path", click "Object to Path". Or simply press "Shift" + "Ctrl" +"C". This steps is required if you have text or other external objects.

Convert objects to path

Step 7-4: Generate G code

Goes to "Extensions" => "Laserengraver" and click "Laser...". A dialog box will jump up. You can select "Directory", "Unites" and modify other preference under "Preference". Under "Laser", type the file name (should appended by .nc extension). Then click "Apply".
Convert the object to G code

A dialog box will say "laser working, please wait..".

If "Draw additional graphics to debug engraving path" is checked under "Preferences" before clicking "Apply", Inkscape will plot a lot of arrows on top of the plot, showing the moves given by the generated G code.

G code is successfully generated! A lot of arrows.

Step 7-5: Pass the G code to RPi

If you use a laptop/desktop to generate the G code, then you have to pass the G code to RPi using ssh or other tools. The G code should be placed under the same folder together with the python routines.

Step 7-6: Make necessary modification to the python code and then engrave!

At least you want to change the G code file name in (line 25). Some other changes, say, pin numbers (line 29, 31, 32), resolution (line 35, 36), engraving speed (38), can be changed if you understand them.

Type "sudo python" in terminal to run the python routines and have fun!