Overview |
|
The Lego RCX is a powerful tool for exploring robotics. However, with only 3 input ports,
it lacks the flexibility of application that a standard micro-controller provides. This is most
apparent when attempting to interface the RCX with a device that provides digital input, such as
a smart sensor or another micro-controller.
A naive approach would use the 3 input ports as digital inputs, restricting the input range to numbers
from 0-7. Another method, utilizing serial transmission is possible. But, when coupled with the
RCX's already low sampling
rate, the serial approach results in transmission rates much too slow for many applications,
such as interfacing with an external
data bus.
To combat these factors, we have chosen to provide digital interface
to the LEGO RCX by converting an 8 bit input
into a coded voltage level to be read by the brick's internal A/D converter.
While this method has the drawback of
converting from digital to analog back to digital,
it does allow the fastest possible transmission of data
while using only a single input port. This provides instant extension of the RCX's range of applications.
|
D/A Conversion
|
|
Here, we'll take a look at the general concepts of digital to analog conversion.
In these schemes, a set of digital inputs is taken as a binary number, which is
scaled to an equivalent voltage level. A bit of familiarity with the binary
number system is helpful -- if you feel rusty, check
here for a quick review.
Voltage Dividers
The heart of any D to A conversion is the voltage divider. One of the most common
circutis in all of electronics, the voltage divider takes a voltage difference and splits
it into two parts. Voltage dividers look like this:
A voltage divider of two resistors is easy to understand -- the voltages across each resistor
are proportional to the values of the two resistors.
Leaving a few details out, we'll mention that when a voltage divider drives a load, that load
can change the operation of the divider. This happens when the resitance (or, more correctly, impedance) of
the load circuit not much larger than the value of the divider's resistors in parallel.
So, a good rule of thumb when using voltage dividers is to either make sure that the load's impedance is more
than 10 times the smaller resistor, or to isolate the divider with a buffer.
If you're interested in learning more about any of the circuits discussed here,
the best reference is the all time classic,
The Art of Electronics, by Paul Horowitz and David Hill.
Online, there's a nice voltage divider calculator
Resistor Nets
It's now easy to see how we can use a set of voltage dividers to encode a voltage level
to the RCX. As a starting point, imagine a circuit with difference voltage dividers,
each enabled by a given switch:
Closing S1 will send a signal of 1 volt, and S2 will send 3 volts. However, S3's
voltage divider will run into serious trouble, because the real picture of what's going on
looks like this:
The LEGO RCX has an impedance of 10k ohms! So, S3's voltage divider will not send the 5 volt level it should.
We can easily fix this by using smaller resistors in S3's divider, but we need to be careful -- setting the values too low will draw excessive current.
We can make as many of these voltage dividers as we wish, but as some point this becomes impractical.
For example, sending numbers between 1 and 255 would require 255 different switches and dividers! Not only is
this a pain in the neck, it also runs into the physical limitations of the resistors themselves, which
have a tolerance of 1% at best.
A better plan would be to use an R-2R ladder, which looks like this:
Leaving the math out, the R-2R ladder makes it easy to encode a binary number as a voltage level. We
can extend the ladder to accept as many digits as we wish by repeating the pattern. Now, instead of needing 255 switches, we can do the same job with only 8, and we only need two resistor values. The only
limitations now lie in the tolerance of our resistors, and the precision of our input voltage.
There's a fairly thorough, if technical,
reference on R-2R ladders online. And of course there's a good section
in The Art of Electronics.
D/A Chips
The problems of resistor tolerance and input voltage precision are solved by using a
manufactured D/A chip. Many of these are produced, most within reasonably low cost. A chip
that accepts 8 bits in parallel, and uses a laser-trimmed resistor ladder in conjunction
with an internally set voltage reference to generate an output voltage costs less than $10.
Choosing among the different D/A chips can be confusing at first. The main differences are:
- # Bits
- You can get DAC's that accept 8, 10, 12, 14, 16 bits or more. The more bits, the
bigger the cost. Since the LEGO RCX can only recognize 1024 different voltage levels, it doesn't make
much sense to try for more than 10 bits.
- Parallel/Serial
-
A DAC can accept bits in parallel or in serial transmission. Serial transmission means you're probably
using a micro-controller or micro-processor to generate the data you wish to send. Parallel is much more
intuitive and easy to work with.
- Package
-
A DIP package (Dual Inline Package) fits neatly into a solderless breadboard, and is by far the
easiest to use for experimenting. A number like 16-DIP means that the chip has 16 pins, 8 on
each side. Be aware that a chip advertising 10 bits of input on a 16-DIP likely re-uses several
input pins, and thus requires a micro-controller to regulate the transmission of data.
- Voltage/Current Output
-
DAC's are available that output current levels instead of voltage levels. The current output DAC's
are actually slightly cheaper, but may be less intuitive to work with.
- Internal Voltage Reference
-
Some DAC's have an internal voltage reference, which is used to turn an input of, say, 5-6 volts into a
reference of 5.00 volts. Since the DAC uses a network of voltage dividers, it's critical to start with
a known voltage level. Having a built-in voltage reference makes a DAC very reliable and easy to use.
A DAC without an internal voltage reference offers a bit of flexbility for your trouble, but
you'll have to construct (or buy, for less than a dollar) a high precision external voltage reference.
DAC's are available online at DigiKey.com, which has an extensive
online catalog. Be sure to check out the datasheet of any chip online before you buy it, to
make sure it does what you want it to.
|
RCX Sensor Ports
|
|
The LEGO RCX has three input ports. Each of these share an Analog to Digital Converter (ADC),
which takes the
voltage level of 0-5 volts across the input port and converts it to a number between 0-1023.
Since the 3 ports share the ADC, which can only look at one port at a time, and since furthermore the
ADC process itself takes some actual amount of time, the RCX has a limited sampling rate. This rate,
running normal Robolab, turns out to be about 330Hz -- a barrier to keep in mind when constructing
a digital interface that requires a large amount of data transfer. Note that the sampling rate
may be raised as high as 4 kHz by using Ultimate Robolab.
Each of the input ports also has a 10k pullup resistor, which means that the impedance of the RCX is
about 10k ohms. This is critical to account for when feeding it with a circuit that relies on voltage
dividers.
|
The Digital Interface
|
|
Now it's time to construct an actual digital interface to the RCX. The interface
we'll make accepts 8 bits of input in parallel, converts them to an anlog signal
read by an RCX port, and then uses driver code to convert the signal back into a number
between 0 and 255.
This interface may be built on a small solderless breadboard in a few hours, for
a cost of around $10, and enjoys a huge range of practical applications.
Unbuffered design
The most basic approach would be to take an 8 bit DAC, such as the AD557, and feed its output
directly to the RCX. The result would look like this:
However, in practice, this runs into the problem of impedance -- the relatively low RCX
impedance interacts with the voltage dividers of the RCX and throws off the results.
Buffered design
Since we can't get inside the chip to change the resistor values, we will isolate the R-2R
network from the RCX by using an op-amp buffer. The op-amp buffer is a simple circuit that
looks like this:
It is an amplifier with a gain of 1: the signal out exactly matches the signal in. This may
not seem useful at first, until we realize that the op-amp serves as a clean buffer which isolates the
voltage dividers from any interaction with its load.
Notice that the op-amp has its own V+ and V-. In practice, most op-amps can only generate output
signals that fall well within this range. Special op-amps, called rail-to-rail op-amps, can generate
signals almost right up to their V+ and V-. However, we'll always do well to make sure that the
V+ is safely greater than the maximum signal value we wish to send, and V- is safely less than the lowest
value.
With this knolwedge, we'll use the op-amp buffer to solve the impedance
problems we encountered with the DAC and RCX.
Parts list:
The DAC input pins are used as follows:
- The 8 input pins D0-D7 get the digital input coming in. D0 is
the least significant bit (the one's place), D7 the most significant bit.
- +Vcc gets 5.4V, and the two GND's get 0V. See below for more on this.
- Vout is the output signal that gets sent to the op-amp buffer
- Vout SENSE A and Vout SENSE B are both connected directly to Vout. These pins
allow the user to insert resistors across them, which are used with an internal
non-inverting op-amp for scaling. We've chosen not to use this option, since scaling
would introduce error from the tolerance of our resistors.
- CS' is a low-true pin that selects this chip. Since this is the only DAC we're using,
we set it to GND, which permanently selects it.
- CE' is a low-true pin that enables the chip. Again, since we're assuming continuous
operation, we set it to GND, which permanently enables it. Note that if we wanted to use
mechanical switches to drive the input, we could debounce those switches by driving CE'
with a square wave from a 555 timer, set with a period of about 1ms.
The circuit is driven by a AA battery pack that gives 6 volts of potential. Since
both the DAC chip and the op-amp we're using have a maximum difference of 5.5V, we
trimmed down the battery voltage using a diode-drop. (The voltage across a diode
is always about 0.6V.)
Note that we used two different diode drops, one to set the DAC potential from 0 to 5.5V,
the other to set the op-amp potential from -0.6 to 4.9V. Although the op-amp has rail-to-rail
output, it did clip the signal close to 0V, so driving it with a little less than that ensures
we'll get our whole output range.
The op-amp is set up as a classic op-amp buffer: a non-inverting amplifier with a gain of 1.
The output of the op-amp provides both the stabilizing negative feedback, and also gives
the final buffered output signal to the RCX.
Since an op-amp does have a fairly slow, by electronic standards, response time, we wouldn't
have the option of using this simple solution in a more demanding application. However, given
the RCX's slow sampling rate, which will never be more than 4 kHz, the op-amp buffer's propogation
delay will never be a limiting factor.
A simple test circuit for the RCX input adapter can be made with an 8-DIP switch, 8 resistors,
and some jumper wires. Wire them up like this:
The resistors (any value between 1K-50K ohms) act as pull-ip resistors to 5V when the switch is
open, sending out a high signal. When the switch closes, the resistors act like top-heavy
voltage dividers, which puts the output at 0V for a low signal. You can flip these bits around
to send out individual binary numbers between 0-255, and see what the RCX receives by viewing
the input port on the LCD display.
Driver Code
In a perfect world, the 2.55V that the digital interface outputs as number 255 would be read
as 510 by the RCX, enabling us to simply divide the port value by 2 to recover our original number.
This approach is almost correct, and can be used in situations where absolute accuracy is not as
important as relative accuracy.
However, instead of reading 2.55V as value 510, the RCX reads it as value 522, while value 0 read
as 0. To make matters worse, a point-by-point analysis of the input showed the scaling to be very
slightly non-linear. So, the driver program to decode the values from the digital interface does
not use a slope, but instead does a binary search to determine which range the value is in, and applies
the appropriate transformation to recover the original number.
Our ROBOLAB driver code is available here.
Performance
The performance if the digital interface is acceptable for many applications, but is far from perfect.
When a single number is sent over a period of time, the RCX will correctly receive that number for
the majority of the transmission. However, noise and the apparent instability of the RCX's internal
ADC conspire to generate incorrect results for some small fraction of the time. These incorrect results
are either one number above or one number below the intended number.
In applications where the relationship between the data is most important, this is often tolerable.
However, in other applications, such as sending precise control codes, an occasional error of +/-1
may be produce erratic behavior. In these applications, it is recommended to use only the
6 most significant bits for data transmission, and tie the two LSB's to ground.
Additionally, in relative applications, it's important to recognize that the error in transmission
is plus or minus one number, not one bit. Sending grey code will not be as effective, therefore,
as sending straight binary numbers.
|
Sample Application: The RCX as a Musical Instrument
|
|
To demonstrate the capabilities of the digital interface, we decided to turn the
RCX into a musical instrument capabale of playing 36 different notes, while using just
a single RCX input port.
Our design used a 12 key input, and 2 octave shift buttons, which were decoded by a
BASIC Stamp, which sent a frequency value to the RCX. The RCX scaled the frequency and
played the appropriate note.
BASIC Stamp
The BASIC Stamp is a micro-controller package, programed in an intuitive version of the BASIC
programming language. Reasonably low in cost, it offers an extremely friendly package for
interfacing with a micro-controller.
We used the Stamp here to drive the keypad and octave shift inputs, and to do some calucation
to determine the frequency to be played. It would have been possible to build up an equivalent
circuit using discrete combinational logic chips, but this would have resulted in a much
less flexible design, and would have required many chips. A compromise solution could have been
to use a programmable logic array to cut down on the number of chips, but the result would still
not have had the flexiblity of the Stamp design.
More BASIC Stamp information is available at
www.parallax.com.
Circuit Design
Since we wished to feed 12 keys and 2 octave shifts into the BASIC Stamp, and get 8 bits out,
it appeared at first that we would require 22 pins. Since the Stamp only has 16 pins, we devised
an arrangement to encode 3 different keys into a single pin, dropping our pin requirements
down to 4 + 2 + 8 = 14 pins.
To encode the keys, we set up the keypad as a 3x4 matrix. The BASIC Stamp has the ability to
measure RC time constants, so we gave each of the 3 keys in a given row different resistor values
and fed them through the same capacitor on the way to that row's pin. In this way, we can keep track
of all 12 keys by checking the RC time constants of 4 pins.
We also put in two octave shift buttons. These were set up with pull-up resistors, so they gave
a high signal when open, and a low signal when pressed.
We fed the 8 output pins directly to the digital interface, and connected the interface to
port 1 of the RCX.
Stamp Code
Click for the full code for the BASIC Stamp .
The Stamp code had three main parts. The first part checked the RC time constants of the 4 keypad pins to
determine which key was pressed. The second computed the frequency for the note, taking any octave
shift into account. Finally, the frequency was turned into a binary number and sent to the 8 output pins.
On the RCX side, the code was a loop which read the value from the digital interface, decoded it,
scaled it to an output frequency, and then played it.
Performance
With this system, the RCX plays 36 different notes faithfully and accurately in real time.
Very occasionally it will slip slightly flat or sharp. The tone quality is not particularly
pleasant -- another project may be to get better audio sound out of the RCX using an output port.
In sum, however, this example demonstrates the ability of the digital interface to extend the
power of the RCX, with minimal cost in processing power and with the use only a single input port.
|
Other Project Ideas
|
|
Here are some other ideas for projects using the digital interface. Note that
some of these ideas will require a deeper familiarity with electronics.
- RCX Keypad
-
Hook up a 64-key keyboard to a BASIC Stamp to encode the key pressed as a
unique number. Output the number to the RCX via the digital interface,
and you'll have real-timekeyboard input to the RCX.
- Absolute Position Sensor
-
Connect a bank of 8 phototransistors to the inputs of the digital interface.
Use graph paper to create a bar-code number for the 255 different positions
along the length of the paper. Add a small light and some baffling to
create a bar-code reader that will determine the absolute position of a robot
in one dimension.
- Frequency Analyzer
-
Feed a signral from a microphone through a low-pass filter made with a resistor
and capacitor. Send the filtered signal into a BASIC Stamp, and let it determine
the frequency of the funadmental by counting the number of zero-crossings in a
given time period. Let it output that frequency as a scaled number through the
input adapter. Now the RCX can respond to the fundamental frequency of a harmonic
sound.
- Combinational Logic
-
The digital interface works well with TTL logic chips, which are available in
AND, OR, NOT, and other configurations. You can hook a different combinational
logic circuit into each of the 8 digital interface inputs. Model different
classifications, like Amy like sandwiches with bacon and lettuce, or cheese
and tomatoes, but never with cucumbers. Or, construct a binary adder circuit
using combinational logic and use the RCX to convert the output to decimal.
- Function Plotter
-
Build a LEGO robot that moves forward in a straight line, and that carries a pen that
can move laterally to a given position. Program a BASIC Stamp to generate a repeating
function, like a triangle wave or a sin wave, and feed the Stamp's output through the
digitial interface to the LEGO robot, which will now draw the function as it rolls
along a piece of butcher paper.
- Random Number Generator
-
Clock an 8 bit binary up counter with a 555 timer, with an RC time constant of about a nano-second.
Feed the output of the counter into a latch register, clocked by another 555 timer circuit with
an RC time constant of around a millisecond, and put a small bulb in series with the resistor. The
uncertainty of the bulb's resistance (which varies with temperature), plus the chaotic interaction
of the two 555 phases, will produce a number that is effectively random. Feed the output of the latch
register to the digital interface, and sample it whenever a random number is needed.
|
Conclusions
|
The digital interface offers a range of possiblities to the RCX, enabling it to be used
more like a full micro-controller, while not compromising its ease of use or standard
capabilities.
Limitations
The digital interface suffers from some instability in the transmission of its data, due to
noise and the varaiance inherent in the RCX ADC. While this instability is never greater than
plus or minus one number, it does make the interface unsuitable for the transmission of 8 bit
critical data, such as control codes or memory addresses.
It's possible to work around this
issue by limiting data to 6 bits, which will ensure perfect transmission of data without compromising
speed. Another approach may be to encorporate an error checking scheme, which would reduce transmission
speed, but could help reduce error significantly.
Possible Improvements
Two improvements suggest themselves: noise reduction, and the elimination of battery power.
Noise could be reduced in a few ways. Shielded transmission lines is one possibility, as is the
insertion of a low-pass filter at the RCX input port -- the speed reduction would not be noticable at
RCX sampling rates. It's also possible to filter noise by signal processing within the RCX, although
this would begin to impinge on speed and tax the RCX's ability to handle other tasks.
The battery pack could be eliminated by using the RCX's powered sensor capability. In initial tests,
we found that this introduced extra noise into the system. However, another design, which we have
not yet tested, seems feasible. This design would send data as a varying current, rather than a varying
voltage, which may be less susceptible to noise, and would have the added benefit of allowing us to
use a current output DAC, which would be slightly cheaper.
Future Work
In the future, we hope to examine the unpowered design outlined above. We also hope to find ways
to similarly extend the output capabilities of the RCX, which would then allow it to interface
with the full array of digital devices, including a data bus and external memory.
|
D. Sculley
for Prof. Chris Rogers TUFTL LAB Tufts University Spring, 2004
|