One member of the design team developed an alternate control scheme, and this control scheme is described in the following sections:



This alternative control system has been developed in attempt to further lower cost as well as gain some practical knowledge in designing controls for the arm.  This chapter includes details on this control system as well as the knowledge gained throughout the controls design.

As mentioned, the first goal of this control system was to reduce cost.  It was earlier estimated that the current control system in development would be in the ballpark of $1000-$2000 dollars, making the controls cost a significant part of the total cost of the arm.  Any reduction in that cost would certainly help with the goal of creating an arm with a practical price tag.

The second goal was simply to have a control system that would operate the arm in its entirety.  The arm has 6 degrees of freedom; therefore, the controls need to be able to actuate all 6 degrees without rearranging any wires (hooking and unhooking various joints/motors).

A third goal was to have a control system with variable speed capabilities.  Variable speed makes fine-tuned motion easier to operate.  It is clear to see how important slow motion is for a manually controlled robotic arm, which may at times be used to do delicate tasks that would be difficult or impossible to do without speed variability.

Finally, a fourth goal was to create a control system that was reasonably easy and intuitive to use.  Because this is an interface between a machine and a human being, human factors becomes an important issue.  The controls need to make sense, be easy to operate, and perform in a reliable and predictable manner.



Like most design problems, some reasonable assumptions can be made in order to get some clear direction for development.  These assumptions turned out to be a crucial part in the shaping of this control system.

The first assumption was that no positional feedback from the arm is required at any joint.  Unlike robotic arms used in industry, which are largely completely automated, the wheelchair arm is manually controlled by a human being who can literally see the position of the arm, providing the only positional feedback necessary.  This assumption helped to simplify the controls a great deal and reduce cost.

The next assumption was that no motor speed feedback was required, again simplifying the controls.  Motor speed feedback (usually in the form of a tachometer) is costly and used mainly for systems that require precision movements.  Because this arm is manually operated, the user can see the speed and vary it accordingly.

The final assumption was that the user as limited dexterity in the hands.  This is a reasonably assumption because the arm is being designed in the hopes that it can be used by a paraplegic or quadriplegic.  Limited hand dexterity, in this case, means that the user is able control the movement of his/her hand, but may not be able to grip things.  As a result, a joystick with yaw control (3-D joystick) would not be a viable option.  This limits us mainly to buttons, switch and a 2-axis joystick similar to the one used to control the chair itself.



The controls consist of two system (not including the motors themselves).  There is the actual control module and there is the amplification module.  The control module is what the user interfaces with to actuate the arm and the amplification module amplifies the control module signals in order to power the motors.

The user operates the control module with a 2-axis analog joystick which has a built-in button.  The x- and y-axis of the joystick are used to allow variable speed control of two different motors in either direction at the same time.  The button is used to select one of four available operation modes.

Figure 11.1 Control Box
Because the arm has 6 degrees of freedom and the joystick has only two, not all arm motors can be controlled at the same time without the use of a very high-level math processor and some rather complicated programming.  To fix this issue, the arm’s operation is broken into four different modes, each controlling a different combination of motors/joints.  The different modes and their joint combinations are shown below in Table E.1.

Table E.1 – Controller Mode Setup







Should Twist


Should Bend



Should Twist


Elbow Bend



Wrist Twist


Wrist Bend



Gripper Open/Close


Elbow Bend



This control module uses a technique called pulse width modulation or PWM to vary the speed of the motors.  This process will be explained in greater detail in the next section.  The signals from the control module are amplified by H-bridges in the amplifier module.  This, too, will be explained in the next section.





Figure E.3 Basic Signal Flow Chart


As mentioned in the previous section, the controls system consists of two modules: the control module and the amplifier module.  The two modules are connected with a 10-conductor cable that carries all of the control signals as well as the power supply and common ground for the control module.

The signals going to the amplifier module consist of the mode enable signals, the x-axis forward and reverse and the y-axis forward and reverse.  The PWM signal is sent across the forward and reverse lines while a steady logic on/off signal is sent down each of the four mode enable lines.  Only one of the four mode lines is on at a time.

The control module houses a custom-made printed circuit board (PCB) which contains the entire control module circuit minus the on/off button located on the box lid.  In order to allow for the board’s easy removal from the box, all of its input/output lines run to a 9-pin Molex plug which connects to the leads of the outgoing 10-conductor cable.  The tenth wire, which is the supply voltage, is routed separately through the power button via two sets of shielded spade connectors.

Figure E.4 - Control Circuit Schematic



The circuit in the control module can be broken up into three main parts: the joystick, the x-axis controller and the y-axis controller.  Both the x- and y-axis controller contain identical hardware with one exception.  The y-axis systems mode enable lines power a set of four LEDs which indicate the current mode selection.  In contrast, the x-axis systems enable lines are the very same lines that run down to the amplifier module.

The joystick is essentially two 10 kΩ potentiometers and a normally-off contact switch (push button).  Each potentiometer is one axis of motion.  A variable output voltage is achieved by applying a low and high reference voltage to the potentiometer.  Using its center tap as the output, the potentiometer is varied by moving the joystick.  This changes the resistance of the potentiometer and, as a result, varies the voltage between the low and high reference voltages.  This is a very common way of achieving analog control in electronics.

The contact switch built into the joystick is a normally-off switch meaning that it is in the off position until pushed.  The difference between a contact switch and a standard button is that a contact switch wasless “play” between the on-state and the off-state.  With an ordinary button, there is some gray area between on and off.  This causes problems with a digital circuit that is trying to interpret whether the switch is sending a high or low signal.  This particular contact switch is used to select the desired operating mode.  The input lead of the switch is connected to the supply voltage.  On the other side of the switch, the output lead goes to the microcontrollers, but at the same time is “pulled low” by a 100Ω resistor.  Because the input of the microcontrollers have nearly infinite input impedance there is no current flowing along the output line of the switch.  Therefore, when the switch is open, the output is connected to ground through the resistor and is referred to as being “pulled low.”  When the switch is closed, the input voltage is passed along to the output and separated from ground by the resistor.  This means that the input to the microcontroller is whatever the input voltage to the switch was, making the switch behave like a binary input, high or low.

The supply voltage coming into the control module is the very same supply voltage that runs the amplifier module and, in turn, the motors.  The supply comes from the two 12V car batteries hooked in series that are mounted on the wheelchair.  This makes a total of 24 volts.  However, because the control module is mostly a digital circuit, it is not designed to run at such a high voltage.  To remedy this, the 24V supply that is input to the control module is run through the power button straight to a 5V voltage regulator.  At is the only thing the supply voltage is connected to.  The rest of the circuit is connect to the 5V output of the regulator which provides a nice steady voltage that is more to the digital circuit’s liking.  With the help of a small filtering capacitor, the voltage regulator also filters out most of the electrical noise created by the motors.

The x- and y-axis control circuits both consist of a microcontroller, and analog-to-digital converter (ADC), and a single 20MHz clock-oscillator which is shared by both microcontrollers.  The microcontroller chose was Microchip Inc’s PIC16F84, the 20MHz variety (they also make an older 4 MHz version).  The ADC is National Semiconductors ADC0831.

The PIC16F84 is an 8-bit microcontroller that has 13 I/O lines.  It has the capability to do simple multitasking with the use of its timer-overflow interrupt feature.  The internal clock speed of the chip is ¼ the input clock speed.  In this case, that means the chip is essentially running at 5 MHz.  It is a relatively efficient chip, taking only one cycle to run an instruction with the exception of program branches such as goto’s and subroutine calls.  One of the most attractive features of this microcontroller is the price.  At about $6 apiece, they provide a good deal of functionality.

The ADC in this control circuit is an 8-bit serial converter.  This particular converter uses a conversion technique known as successive approximation.  This means that the converter determines one bit at a time, starting with the most significant bit (bit 7) and working down to the least significant bit (bit 0).  The process takes about 30 μs to complete, after which it is ready to output the result.  The ADC requires two lines to control.  The first line tells the ADC to start the conversion (the CS line).  The second line supplies the digital clock signal to the ADC in order to get it to send its output one bit at a time.  The ADC also receives a high and low reference voltage to which to compare its analog voltage input.  When the conversion process starts, the ADC takes a snapshot of the input analog voltage and compares it to the reference voltages.  It then outputs an 8-bit number between 0 and 255 that indicates where the analog voltage is between the reference voltages.  For example, if the input is the same as the low reference voltage, then the output would be a binary 0.  If the input is half way between the low and high references, then the output would be 127 (half of 255).  This give the microcontroller a way to understand where the joystick is positioned.

Before explaining how this circuit works as a whole, it is important to understand the process of pulse width modulation and how the microcontroller counts time.  The speed of a DC motor is controlled by voltage, provided that the motor is not approaching its stall current.  The spinning of the motor generates a backwards voltage or back EMF (elecro-motive force) that works against the input voltage.  The faster the motor spins, the more back EMF it generates until the motor reaches a speed where the back EMF and the input voltage are approximately equal.  At this point the motor has reached a stable speed that it will maintain regardless of the load placed on it.  This is all assuming that there is (a) enough current available for the motor to draw from and (b) the motor is not approaching its stall current where it will eventually slow down and stop.

Now, there are two ways to control the voltage level being input to the motor.  The first is to place a variable resistor in series with the motor at the motor’s input.  By increasing the resistance, the voltage drop across the resistor increases thereby decreasing the input voltage to the motor.  This is a rather inefficient and unreliable means of motor speed control.  Plus, it can drastically limit the current being provided to the motor.

The other way to control the motor’s input voltage is through a process called pulse width modulation or PWM.  PWM is nice because the motor is always supplied with the maximum voltage available.  By inputting the voltage in pulses of varied length the effective voltage changes and creates the same response from the motor as applying a constant voltage of the same level as the effective voltage.  This is much more efficient than using a variable resistor to change the input voltage and the current delivery capability is limited only by the power source.

The PWM signal consists of two parts the off-time or off-cycle and the on-time or duty-cycle.  The off-cycle is the period of time that the pulse is off while the duty-cycle is the period of time that the pulse is on.  To determine the effective voltage being generated by the PWM, the formula is


For the PIC microcontroller to generate a PWM signal, it has to have a way of counting on-time and off-time.  This is done by a process called timer interrupt counting.  The timer in the microcontroller is an 8-bit register that counts clock cycle (the internal ones, not the external ones).  After the timer has counted 256 cycles (51.2 μs total) it overflows back to zero and calls an interrupt.  When the interrupt is called, the PIC drops whatever it was doing and goes to the interrupt handler in the code to find out what to do.  After the interrupt instructions have been carried out, the PIC returns to where it was before it was interrupted and continues on.  This allows for a rudimentary form of multitasking because the PIC can be busy doing other things while it counts off time.  To generate a PWM signal, the PIC as a set off-time of 50 timer interrupts, and it varies the on-time between 10 and 110 timer interrupts depending on the position of the joystick.

How the entire circuit works together to control the arm is explained here.  We will still just focus on one axis of motion because the other axis functions the same way.  The process starts when the PIC requests a joystick reading from the ADC.  After the ADC has finished with the conversion, the PIC begins reading it in one bit at a time.  Meanwhile, the PWM is in the last stages of the off-cycle.  When the entire conversion is read in, the PIC determines whether the joystick is in reverse, forward or the dead zone.  The dead zone is the area where the joystick is centered that is about 1/5 the width of the joystick’s entire range of motion (input number will be between 100 and 155).  If the joystick is in this location, the PIC produces no duty-cycle, goes back to the beginning of the off-cycle and starts all over again.  If the joystick is in reverse, the PIC subtracts the input number (between 0 and 99) from 110 and the result is the length of the duty cycle in timer interrupts.  When the joy stick is in the forward position, the PIC subtracts 146 from the input (between 156 and 255) and the result is the length of the duty cycle in timer interrupts.

After determining the duty cycle length, the PIC turns on the forward line for forward or the reverse line for reverse.  Notice that only one of these lines can be on at a time.  During the duty-cycle, the PIC basically just continues to count down the timer interrupts until the duty-cycle is to end.  At the end of the duty-cycle, which ever line was turned on is now turned off and the PIC enters the off-cycle state were it will begin the process all over again.

That procedure goes on indefinitely as long as the controller in turned on.  The only exception is when the mode select button is pressed.  Like the timer overflow, the button pushing triggers an interrupt.  The PIC stops whatever it’s doing, shuts off both forward and reverse lines, changes to the next mode, and then stays in pause loop until the button is released.  At that point, the PIC returns to the beginning of the off-cycle and goes back to normal operation.  The code for both PICs is the identical.  It can be found in Section E.7.

The operation and output of the control module is worthless without some way to amplify the signal to a point that is strong enough to actually power the motors.  This is the reason behind the amplifier module.

The amplifier module has two major parts: the router board and the H-bridges.  The router board does exactly what the name implies; it routes the signals coming from the controller module to the appropriate place.  It is a simple device consisting of 12-pin Molex plug for input, a 2-pin power input, and six 3-pin output.  All of this is connected with a series of wires tracers and diodes.

The other part of the amplifier module is the part containing amplifiers themselves.  The type of amplifier used is called an H-bridge, a device designed specifically for 2-direction motor control.  There are six H-bridges, one for each motor.  All of the H-bridges were made the same for simplicity sake and all of the components were chosen to be able to handle the largest motor of the lot.  All of the H-bridges have one 3-pin input receptacle, two lines to the motor, a supply voltage line and a ground line.  This 3-pin input receives and enable signal (white), a reverse PWM signal (green) and forward PWM signal (red).  These signals are all passed to the H-bridges from the control module via the router board.

Figure E.7 - Router Board Schematic



Both the router board and the H-bridges were made in a similar manner using perf-boards and a silver pen.  A perf-board is a silicon board (like a standard PCB) with 0.1” spaced holes pre-drilled in it.  Each hole has its own copper pad to which things can be soldered.  To make a “PCB” this way, you simply solder your components in place and connect everything by drawing traces with a conductive silver pen.  To improve the physical durability of the otherwise delicate traces, you can cover them with a green overcoat pen or overcoat spray.  In the case of the H-bridges, all of the large current-carrying connections were made with short pieces of 12 AWG wire rather than the traces to avoid burning up the traces.

The components on the H-bridge include: 2 p-channel MOSFETs, 3 n-channel MOSFETS, 2 NPN bipolar junction transistors (BJT), 9 1 kΩ resistors, 4 PCB mount male spade connectors and one 3-pin receptacle.  Note that all of the part numbers are listed on the H-bridge schematic in the figure 11.10 below.  Starting from the bottom of the H-bridge-top image, the spade connectors go as follows: ground, voltage supply, forward out to motor, reverse out to motor.  The 3-pin input will only plug in one direction and the color convention is the same as mentioned above for the H-bridge outputs.

The H-bridge design is relatively standard with the exception of the enable transistor added just before the ground of the board (bottom-most transistor on the image).  All of the H-bridges that are controlled by the same axis of the joystick receive input from the control module at the same time.  The only way to limit activity to one H-bridge at a time is to provide a way to disable all of the others.  This is done by the use of the mode enable lines from the control module along with the enable transistor found on each H-bridge.  By sending a logic 0 (0 volts) to the enable transistor, the transistor is turned off, making the H-bridge an open circuit by disconnecting the ground.  When a logic 1 is applied to the enable transistor (5 volts), the H-bridge becomes grounded and is, therefore, active.  This is how the control system limits the motion to two motors at a time.

Figure E.10 - H-bridge Schematic


There are two motors that get both an x-axis signal pair and a y-axis signal pair.  These are the wrist motors.  Because of the differential system used in the wrist, both motors have to run together to move the wrist in either a twist or bend manner.  For twist (x-axis), both motors run in the same direction.  For bend (y-axis), the motors run in opposite directions.  To do this, the router board sends x- and y-axis signal pairs to both motors.  However one of the motors receives a reversed y-axis signal pair.  This corresponds to output set number 4 on the router board schematic and is also the same set on the actual board when looking at it from above.

Now, with all of these components, we have the makings of the amplifier module.  Hook up a motor and a power supply, input the signals from the control module and we have a motor with variable speed.  There is, however, one problem that can be devastating to the H-bridges.  This problem occurs just before the motor starts moving.  The problem is that when the motor is not turning it is not generating any back EMF and behaves like a simple piece of wire, a short circuit.  This H-bridge design has no current limiting features.  So, during motor startup, if the motor does not start to rotate immediately, there is a voltage drop of 24 volts across the three transistors in the active circuit path.  All of these transistors have an operating resistance in the 10’s of milli-ohm range meaning that the power they are dissipating is in the kilowatt region.  The transistors cannot dissipate much power for more that a short time before they blow.

The simplest way to fix this problem is to put a low-value high-power resistor in series with the motor.  In this case, the best resistance found on short notice was a 5Ω, 50W resistor and a 0.8Ω, 25W resistor.  After PWM, the effective voltage across the motor is about 16V.  That makes the power dissipation across the 5.8Ω resistance approximately 44W.

This may seem like a waste of power, but the only time this much power is dissipated by the resistors is before the motor starts moving.  Once the motor starts to move – even a small amount – the motor’s effective resistance (due to the back EMF) increases dramatically.  So, the 5.8Ω is much less than the motor resistance and, therefore, most of the power is dissipated across the motor.  The only real downside to the setup is that the effective current is limited to no more than about 2.75A.  That’s not strong enough to move the larger motors when they are loaded.

On a final note about amplification, there are several companies that make motor driver integrated circuits (ICs).  One company in particular, Allegro Microsystems, makes the motor driver IC 3952. This chip is a single-inline package (SIP) which has some nice features like current limiting, temperature protection, and dynamic breaking.  One chip alone is only capable of delivering up to 2 A of current.  However, these chips can be wired in parallel to deliver more current.  For example, four chips in parallel would be able to deliver 8 A of current which is enough to drive the shoulder bend motor.  Another plus is that an amplifier made of these chips would potentially be very small.  Also, it is likely that it would only take some minor programming changes to the PICs in order to use these motor drivers with the current control module.



For this prototype design, it was decided to mount the modules in sheet metal boxes.  Sheet metal boxes are inexpensive, easy to make, and easy to customize.  In particular, sheet aluminum was used along with aluminum rivets.

To hold all of the boards in place inside their respective boxes, standoffs were used.  These standoffs are hex-side (1/4’) male/female threaded standoffs.  For the control module, the standoffs were steel,  ½” long and had 6-32 threading.  There were fourteen in all: for on the top and bottom of each corner and another three on the top and bottom around the joystick to prevent the board from flexing and breaking when the joystick button is pushed.  The amplifier module used 4-40 threaded, ¾” long aluminum standoffs between the boards (24 standoff in all) along with 8 4-40 threaded 1.5” aluminum standoffs on the top and bottom of the board stack.  For both the control box and the amplifier box.  The boards are attached to their respective boxes with nuts on the bottom and machine screws on the top which also holds the lid (4-40 threading for the amplifier box, 6-32 threading for the control box).

Inside the amplifier box, the main power connector is a 2-pin Molex plug (female) that enters through the back of the box (refer to Figure E.12).  Inside there are two 12 AWG wires that run under the board stack and up the front with quick splice female spade connectors for five of the six H-bridges.  The ends of the wires are topped off with right-angle female spade connectors to connect power to the top H-bridge.  The connection to the motor from an H-bridge starts as two female spade connectors attached to two 16 AWG wires.  On the other end of the wires is a 2-pin Molex plug (female) which sticks out through the front of the box.  There are six in all.  From the front of the box the power to the motor then goes through a resistor block and then on to the motor.

It’s not important which H-bridges are hooked up to which motors because all of the bridges are the same.  It is, however, very important that each motor’s H-bridge be hooked up to the correct output from the router board depending on which degree of motion the motor is actuating.  The following table is a list of the router board output number (found on the schematic of Figure E.7) and the corresponding motor it must be connected to.  Remember that the actual router outputs physically correspond to those in the schematic when looking at the router from the top.

Table E.2 Router Board Output Hookup





Shoulder Bend


Shoulder Twist


Elbow Bend


Wrist Motor 1 (y-axis reversed)


Wrist Motor 2


Gripper Open/Close


A final bit of information that might be useful pertains to the making of the control module printed circuit board.  Mostly all PCBs are created using the same general process.  You start with a board completely plated with copper on one or both sides.  You mask the copper you want to keep using some form of etch-resistant covering.  Finally, you etch the board using a chemical that dissolves the unmasked copper away.  The most common chemicals used are ferric chloride and sodium perchlorate.  The most significant difference between board making techniques lies in the way the board is masked.

A common form of masking (especially in industry), is the use of a photo-sensitive board.  For this process, a negative of the circuit design is created and then, in a darkroom, the board is flashed with the image, exposing all of the parts that are to be masked.  The exposed parts turn black and the rest is cleaned off.  This process is very fast and precise, but requires a lot of equipment and chemicals.

Another means of masking is the use of an etch-resistant pen and/or etch-resistant decals.  Both of these masking tools are good for quick and dirty PCB creation, but it is nearly impossible to make anything with any amount of precision or detail.  The lack of precision makes this method practically worthless when the circuit contains items such as microchips that have pins that are very close together (0.1” spacing).

Another rather interesting masking technique, the one used to make the control board, it the use of toner transfer paper.  This paper, when printed on or photocopied on with some sort of a toner-based printing system (such as a laser printer) can be ironed onto the copper-clad board just like an iron-on transfer for a t-shirt.  The board and paper are then put into water to dissolve the adhesive that holds the toner to the paper (just like a decal).  The board is then etched and drilled.



The following code was use for the alternative controls system.  This code is to be used with the Microchip Inc. PIC16F84 only.  The code is for both PICs used in the alternative controls system.



;; 16F84REG.INC: PIC 16F84 Registers


            ifndef __16C84REG_INC__


__16F84REG_INC__          equ      1



INDF   equ      0x00

TMR0  equ      0x01

PCL    equ      0x02

STATUS         equ      0x03

FSR    equ      0x04

PORTA           equ      0x05

PORTB           equ      0x06

EEDATA        equ      0x08

EEADR          equ      0x09

PCLATH        equ      0Ah

INTCON          equ      0Bh


OPTION_REG           equ      81h

TRISA             equ      85h

TRISB             equ      86h

EECON1                    equ      88h

EECON2                    equ      89h


RAM_BASE              equ      0ch



;; ===============

C         equ      0

DC      equ      1

Z          equ      2

PD      equ      3

TO       equ      4

RP0    equ      5

RP1    equ      6

IRP      equ      7


;; PORTA Bits

;; ==========

RA0    equ      0

RA1    equ      1

RA2    equ      2

RA3    equ      3

RA4    equ      4

T0CKI equ      4


;; PORTB Bits

;; ==========

RB0    equ      0

INT      equ      0

RB1    equ      1

RB2    equ      2

RB3    equ      3

RB4    equ      4

RB5    equ      5

RB6    equ      6

RB7    equ      7



;; ===============

RBIF   equ      0

INTF    equ      1

T0IF    equ      2

RBIE   equ      3

INTE    equ      4

T0IE    equ      5

EEIE   equ      6

GIE      equ      7



;; ===============

PS0    equ      0

PS1    equ      1

PS2    equ      2

PSA    equ      3

T0SE  equ      4

T0CS  equ      5

INTEDG          equ      6

RBPU equ      7



;; ===============

RD      equ      0

WR      equ      1

WREN            equ      2

WRERR         equ      3         

EEIF   equ      4


;; destination bits

w         equ      0

f           equ      1



PROGRAM_START equ      0

INTERRUPT_START           equ      4




;; D1,0: FOSC1, FOSC0

LPOSC          equ      0

XTOSC          equ      1

HSOSC          equ      2

RCOSC          equ      3

;; D2: Watchdog timer enable

WDTENABLED        equ      4

;; D3: Power up timer disable


;; D4: Code protection disable

CODEPROTDISABLE         equ      16



;; end of 16F84REG.INC




; FILE: control1.asm

; DESC:          This program has two functions.  The first is to provide a variable

;           speed motor control via pulse width modulation based on an 8-bit

;           digital conversion of an analog voltage from a potentiometer.  Note

;           that the conversion is done externally by an analog-to-digital converter

;           (National Semiconductor's ADC0831CCN).  The other function of this

;           is to provide the ability to select the active joint on the arm.  The

;           joint is selected by pressing a button connected to bit 7 of Port B.

;           The joint selection is cycled with each press until the desired joint is

;           activated.  Note that no motor on the arm will function while the button

;           is depressed.


; DATE:          04.08.2001

; VER: 1.0 (04.26.2001)


            list       p=16F84

            radix    hex


            __config         0x3ff2  ; PWRT on, WDT off, HS oscillator, no code protection


; Set up custom file registers

input    equ      0x0c

ontime            equ      0x0d

offtime            equ      0x0e

w_tmp equ      0x0f

stat_tmp         equ      0x10

joint     equ      0x11


            #include <>


            org      0x000

            goto    init



; Interrupt Handler_______________________________________


            org      0x004

            movwf w_tmp             ; ~|

            movf    STATUS,w                 ;  |- Save current state

            movwf stat_tmp                     ; _|

            btfsc    INTCON,RBIF            ; Check for joint select

            goto    btn_intr


            ; This simply counts down the PWM on-time

on_intr            movf    ontime,w                     ; ~|- if ontime > 0

            iorlw    d'0'                  ;  |        ontime = ontime - 1

            btfsc    STATUS,Z                 ;  |        restore state

            goto    off_intr1                      ;  |        return

            decf     ontime,f                      ;  |  else

            call      restore                        ;  |        goto off_intr1

            retfie                           ; _|


            ; These count down PWM off-time, but at certain points

            ; other tasks are performed

off_intr1          movlw d'20'                ; ~|- if offtime > 20

            subwf  offtime,w                     ;  |        offtime = offtime - 1

            btfss    STATUS,C                 ;  |        restore state

            goto    off_intr2                      ;  |        return

            decf     offtime,f                      ;  |  else

            call      restore                        ; _|       goto off_intr2



            ; During this segment of off-time, the ADC is prepared

            ; for outputting the serial signal

off_intr2          movlw d'16'                ; ~|- if offtime > 16

            subwf  offtime,w                     ;  |        cycle ADC CLK 1/2 clock

            btfss    STATUS,C                 ;  |        offtime = offtime - 1

            goto    off_intr3                      ;  |        restore state

            movlw b'00000010'  ;  |        return

            xorwf   PORTB,f                     ;  |  else

            decf     offtime,f                      ;  |        goto off_intr3

            call      restore                        ; _|



            ; For this segment of off-time, the bits are read

            ; from the ADC and stored to "input".  Because only

            ; one bit is read for every timer interrupt (every

            ; 256 clock cycles), the process is slow enough for

            ; the ADC to create nice, stable output

off_intr3          movlw d'8'                  ; ~|- if offtime > 8

            subwf  offtime,w                     ;  |        call bit_read (read/store one bit from ADC)

            btfss    STATUS,C                 ;  |        offtime = offtime - 1

            goto    off_intr4                      ;  |        restore state

            call      bit_read                      ;  |        return

            decf     offtime,f                      ;  |  else

            call      restore                        ;  |        goto off_intr4

            retfie                           ; _|


            ; This section simply counts down all of the

            ; remaining off-time

off_intr4          movf    offtime,w                     ; ~|- if offtime > 0

            iorlw    d'0'                  ;  |        offtime = offtime - 1

            btfss    STATUS,Z                 ;  |  restore state

            decf     offtime,f                      ;  |  return

            call      restore                        ;  |

            retfie                           ; _|


            ; This is the algorithm that handels the joint

            ; selection procedure

btn_intr           clrf       PORTA                       ; Turn off all joints

            bcf       PORTB,4                   ; ~|

            bcf       PORTB,5                   ;  |- Turn off/reset PWM signal

            clrf       ontime                        ;  |

            clrf       offtime                        ; _|

            incf      joint,f               ; ~|

            movf    joint,w             ;  |

            xorlw   d'4'                  ;  |- Determine next joint to be

            btfsc    STATUS,Z                 ;  |  selected

            clrf       joint                 ; _|

lo?       btfsc    PORTB,7                   ; ~|- Loop until button is released

            goto    lo?                   ; _|

            movf    joint,w             ; ~|

            call      joint_tbl                       ;  |- Select the next joint

            movwf PORTA                       ; _|

            call      restore                        ; Restore state

            retfie                           ; Return


            ; This is used to restore the state of the STATUS register

            ; and the "Working" (w) register because the main program

            ; may have been in the middle of using them for something

            ; when the interrupt occured.

restore            movf    stat_tmp,w

            movwf STATUS

            movf    w_tmp,w

            bcf       INTCON,T0IF

            bcf       INTCON,RBIF



; Initializaion ____________________________________________


            ; Chip configuration, set initial values

init       bsf       STATUS,RP0

            movlw b'10001100'  ; ~|- Teach Port B (bits 2, 3, 7 input; all others output)

            movwf TRISB             ; _|

            movlw 0x00                ; ~|- Teach Port A (all bits output)

            movwf TRISA             ; _|

            movlw b'00001000'  ; ~|- 1:1 Pre-scaler for TMR0

            movwf OPTION_REG           ; _|

            movlw b'10100000'  ; ~|- Global Intr On, TMR0 Intr On, RB Intr On

            movwf INTCON                      ; _|

            bcf       STATUS,RP0

            bcf       INTCON,7                  ; Temporarily disable interrupts

            clrf       PORTA

            clrf       PORTB

            movlw d'127'              ; ~|- Start with first input at the "center"

            movwf input                ; _|

            clrf       joint

            bsf       PORTA,0                   ; Activate Joint 0 (see data table for name)

            bsf       INTCON,7                  ; Re-enable interrupts


; Main Program Body ________________________________________


main    bsf       PORTB,0                   ; Clear/Reset ADC

            movf    input,w                        ; ~|

            sublw  d'100'              ;  |- if input < 100, goto rev

            btfsc    STATUS,C                 ;  |

            goto    rev                   ; _|

            movf    input,w                        ; ~|

            sublw  d'155'              ;  |- if input >= 155, goto fwd

            btfss    STATUS,C                 ;  |

            goto    fwd                  ; _|

            clrf       ontime                        ; --- else ontime = 0

            ; Do this stuff while the PWM signal is on

on_loop          movf    ontime,w                     ; ~|

            iorlw    d'0'                  ;  |- Loop until ontime runs out

            btfss    STATUS,Z                 ;  |

            goto    on_loop                      ; _|

            bcf       PORTB,4                   ; ~|- Turn off PWM signal

            bcf       PORTB,5                   ; _|

            bcf       PORTB,1                   ; ADC CLK Low

            bcf       PORTB,0                   ; Tell ADC to start conversion process

            movlw d'50'                ; ~|- offtime = 50

            movwf offtime                        ; _|


            ; Do this stuff while the PWM signal is off

off_loop          movf    offtime,w                     ; ~|

            iorlw    d'0'                  ;  |- Loop until offtime runs out

            btfss    STATUS,Z                 ;  |

            goto    off_loop                      ; _|

            goto    main

            ; Do this to make motor run in forward direction

fwd      movlw d'145'              ; ~|

            subwf  input,w                        ;  |- ontime = input - 145

            movwf ontime                        ; _|  NOTE: 11 <= ontime <= 111

            bsf       PORTB,5                   ; Turn on forward PWM signal

            goto    on_loop

            ; Do this to make motor run it reverse direction

rev       movf    input,w                        ; ~|

            sublw  d'110'              ;  |- ontime = 110 - input

            movwf ontime                        ; _|  NOTE: 11 <= ontime <= 111

            bsf       PORTB,4                   ; Turn on reverse PWM signal

            goto    on_loop

            ; Read in one bit of data from ADC

bit_read          bsf       PORTB,1                   ; ADC CLK High (ADC clock signal high)

            bcf       STATUS,C                 ; ~|

            btfsc    PORTB,2                   ;  |- Carry Bit = bit read from ADC

            bsf       STATUS,C                 ; _|                  

            rlf         input,f              ; Rotate read bit into input

            bcf       PORTB,1                   ; ADC CLK Low


            ; Joint selection data table

joint_tbl addwf           PCL,f

            retlw    b'00000001'  ; Activate Shoulder    (Joint 0)

            retlw    b'00000010'  ; Activate Elbow        (Joint 1)

            retlw    b'00000100'  ; Activate Wrist          (Joint 2)

            retlw    b'00001000'  ; Activate Gripper      (Joint 3)




Table of Contents

Appendix D

Appendix F