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.
E.4 CONTROL DESIGN � GENERAL DESCRIPTION
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.
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.
Figure 11.1 Control Box
Table E.1 � Controller Mode Setup
|
MODE |
JOINT/MOTION |
JOYSTICK AXIS |
|
I |
Should Twist |
X |
|
Should Bend |
Y |
|
|
2 |
Should Twist |
X |
|
Elbow |
Y |
|
|
3 |
Wrist Twist |
X |
|
Wrist |
Y |
|
|
4 |
Gripper Open/Close |
X |
|
Elbow |
Y |
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.
E.5 CONTROLS
DESIGN � DETAILED DESCRIPTION
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
|
ROUTER BOARD OUTPUT NUMBER |
JOINT MOTION/MOTOR |
|
1 |
Shoulder |
|
2 |
Shoulder Twist |
|
3 |
Elbow |
|
4 |
Wrist Motor 1 (y-axis reversed) |
|
5 |
Wrist Motor 2 |
|
6 |
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
;;
SPECIAL REGISTERS�
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
;;
STATUS REGISTER
;;
===============
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
;;
INTCON REGISTER
;;
===============
RBIF�� equ����� 0
INTF��� equ����� 1
T0IF��� equ����� 2
RBIE�� equ����� 3
INTE��� equ����� 4
T0IE��� equ����� 5
EEIE�� equ����� 6
GIE����� equ����� 7
;;
OPTION REGISTER
;;
===============
PS0��� equ����� 0
PS1��� equ����� 1
PS2��� equ����� 2
PSA��� equ����� 3
T0SE� equ����� 4
T0CS� equ����� 5
INTEDG��������� equ����� 6
RBPU equ����� 7
;;
EECON1 REGISTER
;;
===============
RD����� equ����� 0
WR����� equ����� 1
WREN����������� equ����� 2
WRERR�������� equ����� 3���������
EEIF�� equ����� 4
;;
destination bits
w�������� equ����� 0
f���������� equ����� 1
;;
SPECIAL PROGRAM ADDRESSES
PROGRAM_START equ����� 0
INTERRUPT_START���������� equ����� 4
;;
CONIGURATION FUSE
;;
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
PWRUPTMRDISABLED���� equ����� 8
;;
D4: Code protection disable
CODEPROTDISABLE�������� equ����� 16
����������� endif
;;
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 <16F84reg.inc>
����������� 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
����������� retfie
����������� ; 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����������������������� ; _|
����������� retfie
����������� ; 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
����������� return
;
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
����������� return�
����������� ; 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)
����������� end