Friday, 28 September 2012

Inkjet printer teardown - get at those stepper motors!

At last night's BuildBrighton open evening, we set to work opening up an old HP Inkjet printer, using our favourite opening-tools - hammers and hacksaws!


We were after a few parts from inside the printer - namely the stepper motors and linear rods (that hold the print head carriage). Before setting to work with the hammer, we located which parts of the printer we wanted to avoid hitting (too hard)

There's a stepper motor, tucked away in the corner of the enclosure - best go easy down there!

It didn't take long before the plastic casing was off...


And we had hold of a feast of salvaged goodies:


Of particular interest to us was the dc motor (used to make the print carriage travel left-to-right) the nice chunky steel rod with precision made carriage (actually just some moulded plastic with brass rings that slide along the rod - no fancy linear bearings here!), the rubber paper-pickup wheels (for our future lathe project) and of course, the stepper motors (complete with pulley heads and drive belts).

We started to get to work straight away on the stepper motors. They're five-wire connections so already we're considering uni-polar steppers. To find out exactly what we've got, we drew up a table of connections, put an ohm-meter across each of the pins in turn and noted down the respective resistances across each set of pins.

(Here Justin is testing the resistance between pins 1 and 5 - about 60 ohms)

We noticed that all connections to pin three were roughly half the resistance of the others (about thirty ohms). From this table of resistances we worked out that we had a unipolar stepper motor with a common "centre tap" - i,e the centres of both coils were connected together


To work out the wiring for the other coils, we had to do some trial-and-error investigating. We put power onto our centre tap (pin 3) then put a ground connection onto one of the other wires (pin5, we called this pin d). The motor energised, moved slightly and locked into place.

The idea now is to identify the other three pins, such that we can label them pin a, b, c and energise them in sequence a,b,c,d or d,c,b,a to get the motor to spin in either direction.

Here we can see our centre tap (pin3) connected to power, with pin5 grounded and pin1 at the same time.


With pin d still grounded, we then grounded the other three pins, one at a time. Where the stepper motor moved slightly anticlockwise, we'd found our pin c. When the motor moved slightly clockwise, we'd hit upon pin a. When there was no movement in the motor, we'd grounded the (remaining) pin b.
Using this rough-and-ready approach, we successfully labelled all four pins on our stepper motor.


With the pins sucessfully identified, we replaced our bit of wire that poked at the pins, connecting them to ground with some IRF640 power FETs. These are like big chunky transistors, with a flyback diode built into them. By putting them on the ground side of  the coil and activating them in the correct sequence, we managed to get the stepper motor to spin at quite a reasonable rate:



The driver chip is one of our old friends the PIC 18F2455, configured as a USB/HID device. Our custom software simply sends a "command byte" to tell the board which way to spin the motor.
252 = spin anti-clockwise
253 = spin clockwise
250 = stop spinning
249 = change the delay beween pulses.

We found with these steppers, that they ran quickly and quietly with a delay of 2ms between step pulses. We could increase this delay to slow the rate of rotation, but movement got more and more "jerky". A delay of just 1ms caused the stepper to hum without turning at all.

Define CLOCK_FREQUENCY = 20
Define CONFIG1L = 0x24
Define CONFIG1H = 0x0c
Define CONFIG2L = 0x38
Define CONFIG2H = 0x00
Define CONFIG3L = 0x00
Define CONFIG3H = 0x03
Define CONFIG4L = 0x80
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40

UsbSetVendorId 0x1923
UsbSetProductId 0x1694
UsbSetVersionNumber 0x1001
UsbSetManufacturerString "Nerd Club"
UsbSetProductString "USB stepper driver"
UsbSetSerialNumberString "1111111111"
UsbOnIoInGosub input_report_before_sending
UsbOnIoOutGosub output_report_received
UsbOnFtInGosub feature_report_before_sending
UsbOnFtOutGosub feature_report_received

AllDigital
Dim i As Byte
Dim spindir As Byte
Dim state As Byte
Dim dly As Word
Config PORTB = Output
Config PORTA.0 = Input

UsbStart
spindir = 0
state = 0
dly = 10

loop:
      UsbService

      If PORTA.0 = 1 Then state = 0

      Select Case state

            Case 250
            Low PORTB.3
            Low PORTB.2
            Low PORTB.1
            Low PORTB.0

            Case 1
            High PORTB.3
            Low PORTB.2
            Low PORTB.1
            Low PORTB.0
           

            Case 2
            High PORTB.3
            High PORTB.2
            Low PORTB.1
            Low PORTB.0

            Case 3
            Low PORTB.3
            High PORTB.2
            Low PORTB.1
            Low PORTB.0
           
            Case 4
            Low PORTB.3
            High PORTB.2
            High PORTB.1
            Low PORTB.0
                       
            Case 5
            Low PORTB.3
            Low PORTB.2
            High PORTB.1
            Low PORTB.0

            Case 6
            Low PORTB.3
            Low PORTB.2
            High PORTB.1
            High PORTB.0

            Case 7
            Low PORTB.3
            Low PORTB.2
            Low PORTB.1
            High PORTB.0

            Case 8
            High PORTB.3
            Low PORTB.2
            Low PORTB.1
            High PORTB.0

      EndSelect
      WaitMs dly

      Select Case spindir
            Case 1
            state = state - 1
            If state < 1 Then state = 8

            Case 2
            state = state + 1
            If state > 8 Then state = 1

      EndSelect
           
Goto loop

End


feature_report_received:
Return


feature_report_before_sending:
Return


output_report_received:
      'PC has sent us some data - use it here
      i = UsbIoBuffer(7)
      Select Case i

            Case 249
            dly.HB = UsbIoBuffer(1)
            dly.LB = UsbIoBuffer(0)

            Case 250
            state = 250
            spindir = 0

            Case 252
            spindir = 1

            Case 253
            spindir = 2

      EndSelect

Return


input_report_before_sending:
      'we're sending data back to the host
      UsbIoBuffer(0) = spindir
      UsbIoBuffer(1) = state

Return