Archive for the ‘TechArt’ Category

Craft to Art; Construction to Exhibit

Wednesday, April 26th, 2006

Andrea’s doing an amazing job prepping the cabinet for display. While I was painting the primer, the cabinet looked white and ucky like this:

And here’s my wife helping on the first coat:

But bring it to someone with vision and you get a sweet-looking flat grey base coat on the outside:

And a “camel” color on the interior that really makes the coffin shape pop:

Andrea has also “bagged” (sponged) on some bronzing, which looks great:

And I can hardly wait to see the pink (fuschia?!) that comes next, with a crackle coat to follow. Sweet!

Ultrasonic Rangefinder, Part III: Receiver / LogoChip Interface Attempt

Wednesday, April 26th, 2006

I haven’t touched the DIY rangefinder project for a couple of weeks, but I realized I also never wrote up my latest work on it.

Receiver Comparator

After my previous post about building two amplifier stages, I intended to use one of the spare channels on the LM324 as a comparator to “digitize” the amplified receiver signal and provide a clean input to the LogoChip. Unfortunately, the first time I prototyped it was late in the evening when my brain doesn’t work too well, and I built it just like the first two stages–as a linear amplifier. I was really surprised to see more analog waveforms on my scope when I expected sharp edges. At only 24kHz, I didn’t think it should be a slew rate problem, but I wasn’t thinking clearly and just set it aside for the night.

The next day, my error was obvious, and I pulled out the feedback resistor to let the op amp run open loop with infinite gain. It cleaned up the signal, although still not as much as I would have expected. Once the basic circuit was working, I replaced the fixed voltage divider with a 20k trimpot and tuned it as well as I could, trying to find the sweet spot to weed out all the noise but pass all the real signals.

I hadn’t seen it before, but now I wondered whether I was getting some false readings from noise, as John suggested he had encountered when working on similar circuits. I looked briefly at adding a low-pass filter to the circuit (it’s already high-pass filtered by the capacitive coupling from the receiver to the first amplifier stage due to the single-ended op-amp I’m using), but haven’t done it yet. First I wanted to connect it to the LogoChip and see what kind of results I got.

PIC CCP

An ultrasonic rangefinder measures distance by emitting a “ping” and counting the time until the echo is detected; dividing by the speed of sound translates the round-trip time into a distance. Because of the short durations involved, the easiest way to do this on a PIC microcontroller is with the “capture” section of the Capture/Compare/PWM (CCP) subsystem. It uses a high-resolution timer and interrupt circuitry to give a very precise measurement of how long something takes to happen.

I started with John Harrison’s CCP code from his srf_demo.txt example on the TechArt wiki LogoChip with Ultrasonic Sensor page. His code was using the PIC’s CCP module #1; but in my application, I was already using CCP1 to provide the 24kHz signal for my transmitter, so I started translating to use CCP2. The control and behavior of the two CCP channels are rather different, so it wasn’t a matter of simple substitution. Here’s what I ended up with:

Here’s the receiver section of the code:

;------------------------------------------------------------------------------
;   Routines for manipulating CCP2 and timer 3 for capture.
;------------------------------------------------------------------------------

constants [
    [CCP2CON $fba]                      ;   capture/compare/PWM 2 control reg
        [CCPxM-CAP-EVERY #0100]                 ;   capture every falling edge
    [CCPR2H $fbc]                       ;   CCP 2 register low byte
    [CCPR2L $fbb]                       ;   CCP 2 register low byte
    [PIR2 $fa1]                         ;   peripheral interrupt request 2
        [CCP2IF 0]                              ;   timer 3 interrupt bit
    [CCP2-PORT portc]                   ;   uses portc pin 1
        [CCP2-BIT 1]
    [CCP2-DDR portc-ddr]

    [T3CON $fb1]                        ;   timer 3 control register
        [T3CCP2 6]                              ;   timer 3 CCP mode bit 2
        [T3CCP1 3]                              ;   timer 3 CCP mode bit 1
                                                        ;   1x src CCP1+2
                                                        ;   01 src CCP2
        [T3CKPS1 5]                             ;   timer 3 prescale bit 1
        [T3CKPS0 4]                             ;   timer 3 prescale bit 0
                                                        ;   11 = 1:8
        [TMR3ON 0]                              ;   timer 3 enable bit
    [TMR3H $fb3]                        ;   timer 3 high byte
    [TMR3L $fb2]                        ;   timer 3 low byte
]

;   Initialize CCP by configuring timer 3 and enabling capture mode.
to ccp-init
    write CCP2CON CCPxM-CAP-EVERY       ;   config to capture every falling edge

    clearbit T3CCP2 T3CON               ;   set T3CCP to 01 to make T3 src CCP2
    setbit T3CCP1 T3CON                 ;       and T1 src CCP1

    setbit T3CKPS1 T3CON                ;   set T3CKPS to 11 to use 1:8
    setbit T3CKPS0 T3CON                ;       prescalar

    setbit TMR3ON T3CON                 ;   enable timer 3

    setbit CCP2-BIT CCP2-DDR            ;   set CCP2 (RC1) pin for input
end

;   Record starting value of timer 3 and clear capture flag.
global [ccp-before]
to ccp-start
    setccp-before ((read TMR3H) * 256) + read TMR3L
    clearbit CCP2IF PIR2
end

;   Wait for capture event and return duration.
global [ccp-after]
to ccp-wait
    waituntil [testbit CCP2IF PIR2]     ;   wait for capture interrupt
    setccp-after ((read CCPR2H) * 256) + read CCPR2L
    output ccp-after - ccp-before
end

I added code to send a ping and take a measurement:

;------------------------------------------------------------------------------
;   Top-level routines to tie it all together.
;------------------------------------------------------------------------------

;   For the sake of testing, activate on powerup.
constants [[standalone 0]]
to powerup
    pwm-init
    ccp-init
    if standalone [ pwm-on ]
end

;   Send a short burst of tone.
to ping
    pwm-on
    mwait 1
    pwm-off
end

;   Ping and measure time to reply.
to range
    ccp-start                           ;   record start time
    ping
    output ccp-wait                     ;   wait for echo and return duration
end

Wrote a little loop to display the results on the PC, and was disappointed to see that they really didn’t vary at all in proportion to the distance from the sensor to an obstacle. After a few minutes of head-scratching, I noticed that I hadn’t wired the comparator output to the LogoChip’s CCP input. Oops! And that’s when I realized I had a much bigger problem.

Overloading Port C1

The PIC’s CCP modules are implemented in hardware, and they’re hard-wired to specific pins. The input pin for CCP2 is the same as general-purpose pin C1–in fact, most if not all of the PIC’s pins have multiple functions that are selected by configuration registers.

My problem arose because C1 is already being used by the LogoChip firmware–as the Go/Stop input! Because LogoChip Logo isn’t open-source, I can’t see exactly how it’s being used, and have to guess what would happen if I tried to use it as a capture input. Since pressing a button attached to that pin makes the LogoChip stop executing user code and return to an idle state, I can’t imagine I’d have an easy time overriding that behavior and getting it to use the pin solely for CCP with no interference.

So what now? I need both CCP modules–one to use the PWM output to drive the 24kHz transmitter, and the other to watch and count time on the receiver. I don’t think I’ll be able to overload C1 with CCP2 for the receiver, so I’m left with a couple of options: swap the pins, or use CCP1 for both transmission and reception.

Swap the Pins

My first thought was to use CCP1 as the receiver (since its corresponding port, C2, is otherwise unused) and make CCP2 the transmitter (on port C1, the Run/Stop button). John says he has previously overridden C1 and used it as an output when the Run/Stop functionality wasn’t needed, so this should work.

In the long run, though, I’m a little uncomfortable giving up the Run/Stop button. I’d like to be able to integrate this technology into hobby robots, and I’d like to be able to leave them powered up but in an idle state, without having to duplicate the preexisting Run/Stop behavior myself in software. Swapping the PWM-transmit / capture-receive pins should work for a quick fix, but I’m not sure it’s where I want to be in the larger game.

Use CCP1 for Both Transmission and Reception

Alternately, I could overload CCP1 for both transmitter and receiver. There’s precedent–another student in class is using the Parallax PING))) (TM) sensor module, which has only three pins–ground, power, and bidirectional signal.

To do that, I’d need to make sure that transmission and reception don’t interfere with each other. Keeping transmissions out of the receiver circuit is easy–put a diode from the comparator output to the LogoChip so the transmitter signals don’t go “upstream” into the comparator.

Keeping comparator signals out of the transmitter driver is a little trickier, but I think I have a reasonable solution, based on something I was considering doing anyway. I’d like to be able to drive multiple sensors from one LogoChip, but there’s only one (er, two, maybe, sorta) PWM output available. To drive multiple rangefinders, I’d need to multiplex the PWM signal somehow–and there are plenty of ways to do that.

The most straightforward is to use a few LogoChip output pins to select which transmitter to drive and AND (or NAND) them with the PWM signal. Cake! And it tidily solves my receiver-interfering-with-transmitter problem–the receiver can dump whatever it wants onto the PWM output, but it won’t go anywhere harmful unless one of the transmitter select lines is activated.

Sounds like a win all around, and I think I’ll investigate it as soon as things calm down with the exhibit and I can get back to tinkering. It means a little more work on the software side (switching CCP1 back and forth between PWM and capture modes), but I’ve never been afraid of writing code.

Cabinet Construction

Monday, April 24th, 2006

While Andrea’s been working on editing video and searching for materials, I’ve been slowly building the cabinet that will house the project–and too busy to upload all my pictures. Here’s an overview of the process.

Large Sheets of Plywood

It all started a little over two weeks ago, at Lowe’s with two sheets of 15/32″ plywood in the back of the Possum Van. The cabinet is about the size of an arcade game, and they’re normally made from ~3/4″ plywood; but this won’t have to stand up to the same kind of abuse they take, so I figured ~1/2″ would be fine. It also reduces the weight dramatically, making it less difficult to lug around.

Plywood in the Back of the Van

A friend and his son helped with some of the initial cuts. Because my tablesaw isn’t very accessible, and I don’t have an extension table anyway, we were cutting plywood on the floor (on 4×4 supports) using my circular saw, and the factory edge of another plywood sheet as a guide. I picked up a new Freud blade for under $15, and it’s incredible–very sharp, very easy to push, very clean cuts. We were all amazed. No more $7 Piranha blades for me!

Ripping Plywood

Starting the Base

For load-bearing elements (the top and bottom of the base cabinet, the bottom of the upper cabinet, and the inner back of the upper cabinet), I used 3/4″ plywood that I had on hand. After cutting all the pieces for the base, I leaned them together to make sure they were sized correctly to fit the way I intended.

Cabinet Base Leaned Together

Not shown here is assembly of the cabinet pieces. I used my biscuit joiner for the whole thing. The biscuit joiner is basically an angle grinder with a very small (3″) circular saw blade and a fancy fence. You hold it up against the edge of a board, squeeze the trigger, and push it against the wood; it cuts a little slot in the wood. You repeat that on the opposing edge that you want to join; then take “biscuits,” little pieces of compressed beechwood that look like flattened footballs, jam them into the slots with glue, and have a pretty solid joint with (theoretically) perfect alignment. Since I was working alone most of the time, it would have been difficult to shoot a picture of the biscuiting process.

Building the Picture Frames

The front of the cabinet will have three swinging “picture frames,” which I made from maple that I had lying around. I used through mortise and tenon joints on the corners for strength, and cut them on a friend’s tablesaw using his tenoning jig.

Tenoning Jig

The joints fit pretty snugly, so they didn’t take much clamping during glue-up. (Love the random white-balance shifts my camera makes on indoor shots!)

Gluing up Picture Frames

Back to the Shop for the Rest of the Cabinet

Because the cabinet’s side panels are continuous from top to bottom (they’re on the outside, not interrupted by any horizontal elements), they had to be glued on last, so I had all the other parts of the base assembled before adding the sides. I wasn’t sure yet how smoothly the glue-up was going to go, so I did them one at a time. In order to seat the biscuits as well as possible, I ended up locating a clamp over each one. You can never have too many clamps.

Gluing up Cabinet Base

After completing the base, I glued up the outer frame of the upper cabinet. (It’s sitting on the assembled base.) Due to the design of the interior, I knew I was going to have to add the coffin panels last–and this meant that the outer frame would be unsupported whilst gluing it up. I clamped on a couple of pieces of scrap plywood to hold it square during assembly until dry. Once again, one pipe clamp over each biscuit.

Gluing Upper Cabinet Exterior

Because the upper cabinet is so large, I was really concerned about the integrity of its corners when I turned the outer frame upright–but I had nothing to worry about; it turned out to be surprisingly sturdy. I test-fit the panels for the coffin liner, then cut the liner fronts from more maple stock, using my tapering jig on a tablesaw. I left them a bit long so I could fit them exactly once I got them back to the cabinet–then regretted having done so, when I didn’t have a good way to cut them to size back at the shop.

I biscuited the fronts onto the liners and let them dry, then fitted the entire assembly into the outer shell and biscuited the outer liner ends to the shell ends, the fronts to the shell edges, and the inner liner ends into the shell sides. I needed gravity’s help during assembly, so I built one liner at a time with the cabinet laying on edge, then turned it upright to clamp and dry. I used scrap stock to hold the inner liner ends tightly against the cabinet shell across their entire width.

Gluing Left Coffin Liner

The biscuit joints on the right liner ended up a little more snug than those on the left, so I used a clamp per biscuit to pull them together. I would have used C-clamps for the entire face-to-shell joint, but I only have four 4″ clamps, so they’re all on the bottom section. The weight of all the pipe clamps sticking out the right side made the cabinet almost a little tipsy.

Gluing Right Coffin Liner

It’s not easy to see from this shot, but the coffin back is recessed a few inches into the cabinet, leaving a “service area” between the false back and the actual back door. That made it tricky to clamp the coffin back onto the coffin edges. I laid the whole cabinet upside down across a concrete ledge and a bucket (suspended to leave room on the bottom to attach clamps), stacked scrap 2x6es above the biscuits, laid a longer 2×6 across each end, and clamped that down tightly to the cabinet.

Gluing Coffin Back

I’m particular enough that I know I would have clamped it tightly like that anyway. However, in this case it was actually necessary–the coffin back was bowed about an inch and a half from end to end, so the top popped completely clear of its biscuits while clamping the bottom. Some of the biscuit joints were pretty loose, so I was really nervous it was going to spring open when I removed the clamps–but it held very nicely (thank goodness). If we do have any problems with it, I can always put some nails in from the back.

Finishing Touches

I needed a notch in the back of the base, for the power cord to come out when the back door is closed:

Base Notched for Power Cord

While the coffin back was drying (I gave it a long time, to be safe), I borrowed a rotary rasp and ground out the notch for the cord.

Notching Base with Rotary Rasp

Putty

My cuts and joints weren’t perfect, and I had some cracks to fill. (They would have been better had I been able to use a tablesaw for the large pieces, but still not perfect.) I gooped them up pretty nicely with some painter’s putty and a putty knife, then did some final sanding to smooth up the plywood before priming.

Puttying Cracks

Primer

Because plywood just drinks up paint, I put two coats of oil-based primer on all of the visible (exterior) surfaces, and a single coat on all of the interior (back-side) surfaces to help seal against humidity changes. The primer said it dries to topcoat in only eight hours, and I was very impressed with how dry it was by this morning. I haven’t uploaded those pictures yet–they’ll come in the next post.

Cabinet Modeling

Tuesday, April 4th, 2006

Andrea and I envision the cabinet for our TechArt final project, A Woman’s Mind, being built in two sections, for ease of hauling it around. The large, upper portion will contain the visible elements of the exhibit; and the small, lower portion will house the computer, UPS, LogoChip, cooling fans, etc.

Tonight, I modeled the upper portion of the cabinet, to get a better feel for the proportions, and to have something more concrete to use when discussing construction details with Andrea. I used an amazing new CAD package called CardBoard (TM). Its user interface is incredibly intuitive; and in addition to the basics like Cut and Paste, it offers operations I’ve never seen in other CAD software, such as Slice, Fold, and Tape.

As you can see below, it has stunningly photorealistic, three-dimensional renderings, even going so far as to simulate shutter shake and mismatched white balance across multiple views.

Here’s the upper portion of our cabinet with all of the screens closed. Note that the picture-frame of the outer screen is excessively wide; I hadn’t yet figured out how to model it at a narrower setting.

Cardboard Cabinet Model, Front View

The outermost panel obscures the entire contents; opening it reveals smaller screens, and begins to expose the shape of the cabinet interior. Again, the picture-frame is a bit wide and not necessarily to scale.

Cardboard Cabinet Model, Front Panel Open

Opening all of the front panels reveals the entire shape of the cabinet interior; as well as the head (monitor), heart, and fertility mechanisms (not yet modeled).

Cardboard Cabinet Model, All Panels Open

The rear panel will be locked and will open only for maintenance, providing access to a shallow false back and to the space surrounding the false interior. These spaces will hold the wiring needed to connect the sensors and actuators to the LogoChip, as well as the cables from the computer to the head monitor.

Cardboard Cabinet Model, Back Open

I plan to model the lower portion tomorrow night, working from the outline drawing of my earlier post. Hopefully Andrea and I can talk it over in class Thursday, and I can start actual construction this weekend.

Cabinet Plans: First Draft

Monday, April 3rd, 2006

First Draft of Cabinet Design

Multiplexing Ultrasonic Sensors

Monday, April 3rd, 2006

Last week in class, we talked about the potential need to have multiple Devantech SRF-05 ultrasonic sensors connected to one LogoChip. Different LogoChip output pins could connect to the different sensors’ trigger inputs, and then the sensors’ echo signals could all feed into one LogoChip input (because only one would be triggered at a time). We were trying to draw how to connect them together without burning them up, and I knew there was a right way to do it but couldn’t think of diodes.

Here it is:

Schematic to Multiplex Ultrasonic Sensors to One Digital Input

The echo signals are TTL, active high. That means that when the signal comes back, the sensor’s output will change from 0V to 5V. Put another way, 0V is normal; 5V means an echo was detected.

The diodes are one-way “valves” that allow electricity to flow from a sensor to the LogoChip when the sensor’s output is high (echo detected), but not from one sensor to another, under any circumstances. This protects the sensors from shorting each other out. When all of the sensors’ outputs are low, no electricity flows through the diodes to the LogoChip, so the pulldown resistor connects the LogoChip’s pin to ground (weakly) for a default input of low.

You could use some of Tom’s multiplexing techniques to connect even more ultrasonic sensors, but at $25 each, I expect cost will be the issue before running out of LogoChip pins.

Ultrasonic Rangefinder, Part II: Receiver

Sunday, March 26th, 2006

Last night, I prototyped the transmitter circuit; today, I worked on the receiver. Coe’s design uses a two-stage op-amp circuit, with AC coupling on the input from the transducer to the first stage, to amplify the received signal before sending it to a comparator. I wanted to do the same, but I prefer to run from a single supply voltage, so I used an LM324 and added voltage dividers to bias the signal up to 2.5V.

First, I powered up the circuit from last night and measured the receiver’s signal on my scope. With the transmitter and receiver about 2” apart, the receiver signal was about 2V peak-to-peak, attenuating to about .5V p-p at 2’. If it continues to attenuate by a factor of 10 every 2’, then to measure distance out to 10’ (round trip of 20’), the received signal would be 2 * 10-10, or .2nV. Let’s hope that’s not the case!

The Circuit

Each stage of the amplifier circuit is taken directly from the LM324 datasheet, “AC Coupled Inverting Amplifier” (although the two stages are DC coupled). The receiver’s signal is AC-coupled to the first amplifier’s inverting input, with a 2.5V bias to the non-inverting input.

Ultrasonic Receiver Amplification Schematic

I’m not sure why C1 is needed on the bias voltage divider, but the output waveform was considerably cleaner with it than without, so I left it in. I also don’t know what RB does, and Forrest Mims’ Engineer’s Mini Notebook on op-amp circuits didn’t show it but the datasheet did, so I left it in as well.

Values

The bandwidth-gain product for the LM324 is 1MHz, so a 24kHz input means the maximum possible gain is about 41.7. The gain is set by the quotient of the feedback and input resistors, and it worked very naturally to select RF = 1MΩ and RIN = 24kΩ.

According to Mims, CIN should have a value of 1 / (2π flow RIN), where flow is the lowest frequency to pass the filter. This gives CIN = 1 / (2π 24kHz 24kΩ) ≅ 280pF–except the first time around, I mistakenly calculated using RF (1MΩ) instead of RIN (24kΩ), and got 6.6pF. I had a 10pF on hand, so I substituted it; but it was still far too low a value, as will be seen shortly.

I breadboarded the circuit on my workbench and measured about .04V peak-to-peak directly from the receiver element, with both transducers pointed at the ceiling. (That was about an 8’ round trip, so my dire prediction of .2nV was fortunately not the case.) Next, I measured only about .08V p-p at the output of the first amplifier stage, so obviously something was wrong. It was at this point that I added C1, which brought the amplifier output to about .1V and cleaned it up dramatically–but with a gain of 40, it should have been more like 1.6V.

I was suspicious about the value of the AC coupling capacitor, CIN, and began substituting different values for it, with the following results:

Condition Signal Amplitude
direct transducer output .04V
CIN = 10pF, C1 absent .08V
CIN = 10pF, C1 = 10uF .1V
CIN = 100pF .5V
CIN = 1nF .6V
CIN = 10nF .6V

It looked like I must have miscalculated by an order of magnitude (at this point, I hadn’t yet caught my frequency error in the calculation), and 100pF was probably close to the best valued, but still a little too far down the knee of the filter’s response curve. .6V output was still a little low for a gain of 40, but within a range I was willing to accept, given that I was estimating the values by counting hashmarks touched by a dirty, wiggling waveform on my scope. I put the 1nF back in and called it good.

Second Stage

After honing the values on the first stage of amplification, the second stage was easy–just more of the same. I used all the same values, but omitted the AC coupling capacitor, since I’m happy to DC-amplify around the 2.5V bias. The second stage gives me a trapezoidal waveform (clipping both the top and bottom of the transducer’s sine wave) running rail-to-rail of the LM324′s advertised output capacity–from 0V to about 4V. Tomorrow I need to run that through a comparator to clean it up just a little more, and then steal John’s capture/compare LogoChip code to start timing the echoes.

DIY Ultrasonic Rangefinder

Saturday, March 25th, 2006

Ultrasonic rangefinders detect objects and measure distance the same way as a bat: Emit a high-pitched “ping” and measure how long it takes the echo to return. The speed of sound in air is nearly constant (ignoring slight variations due to air pressure and humidity), so the time from ping to echo translates directly into the distance to the object.

I’m interested in ultrasonic rangefinders for both hobby robotics and our TechArt final project. They’re available commercially, but $25 each adds up pretty fast if you need multiples to establish a view all around a bot or across the wide front of an art installation. All Electronics has transducer elements for $1 each in quantities of 10 or more, so I ordered a batch of them in hopes of building a rangefinder myself. At $2 each (two transducers, for send and receive), I can add a fair bit of supporting circuitry before hitting the $25 mark.

The Plan

I’m basing my circuit on a design by Gerald Coe at http://www.robot-electronics.co.uk/htm/srf1.shtml, and adapting it for different design goals. His circuit uses a dedicated PIC to provide the oscillator, a MAX232 to generate 16V to drive the transmitter, and 40kHz transducers. For now, I want to run my rangefinder from an existing LogoChip that’s also doing other work, avoid the complexities the MAX232 adds, and use transducers with a different nominal frequency. Later, I might build separate modules intended to stand alone and run with very low power.

Initial Testing

According to a comment on the All Electronics page for the transducers I ordered, they run at 24kHz. The first order of business was confirming that operating frequency.

I hooked my function generator to my frequency counter and scope and dialed in 24kHz, to make sure I was in the neighborhood before connecting the transducer. I then connected one transducer to the function generator to serve as the transmitter (with the frequency counter still attached), and the other transducer to the scope to serve as the receiver.

When I pointed the transmitter at the receiver, a signal showed up on the scope; when I pointed it away, the signal abated. I could bounce it off my hand and receive it, but not off the ceiling. (I’m guessing the elements weren’t aimed well enough and/or the amplitude wasn’t high enough.) And changing the oscillator frequency confirmed that 24kHz is indeed optimal.

So the project is at least possible. That’s a good start!

Connecting the LogoChip

I really didn’t feel like disassembling my balance-bot project, so I’m sure glad I bought several PICs! I built up a breadboard with another LogoChip on it and verified operation. Then I took my motor-control PWM code and cleaned it up to generate a single frequency signal.

Testing with my frequency counter and scope hooked up, it looks like I need timer 2 with a prescalar of 1 and a period of 82 to get as close as possible to 24kHz. Hm, 82 * 24k ≅ 2M, which tells me that I really don’t understand what timer 2 is using for an input clock. Wait–yes, I got it. The PIC has an internal 4x increase in oscillator speed, so the 2Mhz timer oscillator leads to the 10Mhz clocking.

Driving the Transmitter

I first tried powering the transmitter element with an NPN driver, for simplicity and to allow experimentation with the drive voltage:

Ultrasonic Transducer Driver using NPN Transistor

I connected the receiver element to my scope to detect the signal, and was surprised to detect nothing. I looked back at Coe’s schematic and noticed that he drives his transmitter in a push-pull arrangement using the MAX232, so I scrounged around for something with totem-pole outputs that I could use to test. The quickest thing I could come up with was a 7404:

Ultrasonic Transducer Driver using LS7404

And this time, I did show a received signal on the scope, albeit a slightly weak one; so I guess the push-pull drive is necessary.

I’m not satisfied being restricted to a 5V drive, because Coe specifically mentions using 16V to get adequate detection at greater range. However, I’m not sure I have anything on hand that will do exactly the right job and which I’m happy using. None of the options quite work out:

  • The 74xx chips with “high-power output” and 754xx peripheral drivers run open-collector, and I don’t see a good way to use that to provide push-pull.
  • The 754410 H-bridge driver adds about $2 to the cost–not bad, but I’d rather avoid it if I could.
  • The MAX232 adds about $1 plus numerous supporting components–and Coe mentioned that it generates enough noise that he shut it down after each ping to keep it from interfering with the echo detection circuitry.

I’ll probably prototype with the 754410 since I have some on hand, and keep looking for other options.

LogoChip: Small Motor Control

Wednesday, March 8th, 2006

LogoChip Motor Control

Yesterday after class, Steve Atwood and John were talking about controlling a small motor from one of the LogoChip’s output ports. Steve had wired the motor from the LogoChip to ground, and when he activated the output port, the motor would barely spin.

The problem is that the chip on which the LogoChip is based can’t source a lot of current, so it can’t provide enough power to run the motor (even a small one). There are a couple of other ways to wire the motor that work better (which I’ll show below), but first, let me try to explain why it doesn’t work when it’s wired the simple way.

Source and Sink

Imagine a T-fitting attached to a faucet, with the bottom draining into the sink and the side leg connected to a hose. (This is almost exactly like the faucet fitting on a roll-up dishwasher, except the dishwasher has two hoses and we have only one.)

The T-fitting has a valve in it that you can turn, which connects the hose to either the faucet or the sink. So if you turn the valve to the faucet position, you can supply (“source”) water to the hose; if you turn the valve to the other position, you can put water in the other end of the hose and have it drain out into the sink.

One last complication: You only open the faucet enough to supply a trickle of water, not a torrent. But the bathtub is nearby, and you can open its faucet all the way to get as much water as you want.

If you wanted to use the water to spin a water wheel, what would you do? Your first instinct would be to set the valve so that the faucet supplies water to the hose, and hold the hose over your water wheel. That would work–sort of. Because the faucet will only supply a trickle of water, you only get a trickle into your wheel, and it doesn’t turn very fast.

Although it’s counterintuitive, you can actually spin the wheel faster by running a hose from the bathtub faucet (open wide) to your water wheel, then holding that over a funnel into the hose to your sink, with the valve (remember the valve?) set to drain water from the hose into the sink. The bathtub supplies all the water you want, the wheel spins, and the valve drains water down the sink as fast as the bathtub supplies it.

That’s a reasonable parallel for how the circuitry works on the output pins of our LogoChips. They’re not able to source a large amount of current (a trickle of water from the faucet), but they can sink quite a bit (sending the bathtub’s water down the drain).

Active High

Last night, I tested controlling a small motor in three different ways from my LogoChip. First, I hooked it directly to the LogoChip pin and to ground, so that when the pin was on, the motor ran. This type of arrangement is called “active high,” because when you want the motor to be active, you make the voltage on the chip’s pin high.

Motor Driven from PIC Port, Active High

To turn on the motor, I set the port’s value to 1 (setbit). This made the port output +5V, causing power to flow from the pin through the motor to ground. (Engineers, pardon me for using positive current flow, but there’s no point in getting into that much detail in this class.) The motor spun, but weakly.

Active Low

Next, I tried a configuration called “active low,” in which you set the chip’s pin to a low voltage to make the motor active. To set this up, I wired the motor from the pin to the +5V power connection, instead of to ground.

Motor Driven from PIC Port, Active Low

Then to activate the motor, I set the port’s value to 0 (clearbit), so that the pin’s voltage dropped to 0 and power was coming from +5V through the motor to the pin. The motor spun much faster, demonstrating that the chip is able to sink more power than it can source.

Transistor Driver

Finally, I tested using a separate transistor to power the motor. I had a suspicion that even though the motor ran faster in an active-low configuration, I might be able to get yet more performance using a separate transistor.

Motor Driven from PIC Port, NPN Transistor Driver

In this circuit, the LogoChip port goes high (+5V) and sends a small current (5mA) through the base-collector (B-C) junction of the NPN transistor. The transistor has a beta (amplification factor) of about 200, so that permits an emitter-collector current (E-C) of about 1A–enough that I’m pretty sure the transistor is in saturation, even though I haven’t checked the datasheet.

In non-geeky-electronics terminology, the transistor is working like a relay. A small amount of power through the relay coil controls a large amount of power through the relay’s contacts. In the case of the transistor, one wire (the collector) is shared between the low-power coil circuit and the high-power contact circuit. All the stuff with the numbers is just calculating the right value(s) of resistor(s) to use based on your circuit and the characteristics of your transistor.

And it worked as expected. The motor spun noticeably faster with the transistor driver than it did even in the active high configuration.

Stuff for Steve

I dug a couple of salvaged transistors and resistors out of my parts bins, soldered longer leads onto them, and brought them to work today for Steve to try out. I’ll be interested to see how much difference it makes for his motor. And like Tom McGuire, I have plenty of stuff saved up, so the offer’s open to anyone in class if you need help with circuits or components.

LogoChip: Audio Playback Demo

Tuesday, February 28th, 2006

Over the weekend and last night, I’ve put together a demo of using sensors and triggers with the LogoChip. The demo uses one of the built-in A/D converters to monitor a CdS photocell, and then trigger audio playback on a Radio Shack 276-1323 recording module.

The code watches for the light level to dim and then triggers one of two recordings, the idea being that someone is probably standing over the box looking into it. It’s actually a bit complex, because I keep a running average of the recent brightness, to make it easier to tell whether a sudden drop is a significant event or just noise variation on the sensor. LogoChip Logo doesn’t have terribly good support for arrays, and it was fairly interesting writing ring-buffer code.

Adapting the Playback Modules

[INSERT PHOTO OF CIRCUIT IN BOX]

The little PCBs on the sides are the Radio Shack audio playback modules. Each has an offboard record button and an onboard playback button. I desoldered the 9V battery clip that came with the units and soldered on leads to take power from my PCB, to cut down the number of batteries I had to install. I just now realized I had mistakenly plugged the power into the regulated 5V instead of the unregulated 9V, so that may explain why the playback was relatively quiet. It also speaks well for a wide supply voltage range on the modules.

The playback buttons are NO with pullup resistors, and ground their line when closed. Because they’re rubber pushbuttons with graphite contacts the press directly onto the PCBs, there were no leads to solder my remote trigger wires onto, so I wrapped them around the lower leads (toward the middle of the PCB) of the pullup resistors, R3.

[INSERT CLOSEUP PICTURE OF MODULE PCB]

Then I plugged the remote triggers into ports C6 and C7 on the LogoChip. Since the playback buttons on the modules are active low, I had to reverse my software logic and set the ports high on initialization, then pull them low to activate.

;   Configure the audio trigger I/O port.
to init-squawk-port
        ;   Set left and right triggers off (active low, so set high)
        setbit squawk-left-bit squawk-port
        setbit squawk-right-bit squawk-port

        ;   Set left and right triggers as outputs
        clearbit squawk-left-bit squawk-ddr
        clearbit squawk-right-bit squawk-ddr
end

;   Trigger the external playback modules
;   Parameter: which module to trigger
to squawk :squawk-bit
        ;   Trigger it (active low, so set low)
        clearbit :squawk-bit squawk-port

        ;   Wait a smidge to be sure it registers
        wait 1

        ;   Clear the trigger (active low, so set high)
        setbit :squawk-bit squawk-port
end

The Software

[INSERT DETAILED DESCRIPTION OF RUNNING AVERAGE FUNCTION]

I learned several important lessons from this programming exercise:

  • The A/D converter needs longer than .1 seconds between readings–at that repeat rate, I was getting garbage every time. .2 seconds appears to have been working reliably.
  • The LogoChip Language Reference gives the positions of global variables m and n incorrectly, which led to a buffer overflow in my code. Global n is actually position 0 and m is 1, not 1 and 2 as stated.
  • LogoChip Logo does bizarre things to arithmetic expressions. I have no idea how it was evaluating

    setsum-bright sum-bright - global (array-base + array-index) + bright

    because I couldn’t figure out any sequence of evaluation that led to the results it was giving me. I solved it with parentheses:

    setsum-bright (sum-bright - global (array-base + array-index)) + bright

    but it’d be nice to understand what was happening.

The Code

Here are the programs:

  • squawk.txt – Test code to play back sound samples
  • light-level.txt – Test code to monitor and report light levels
  • light-demo.txt – Program to monitor light levels and trigger audio playback

Here’s the code:

;   Keith Neufeld
;   27-Feb-2006
;
;   LogoChip program to demo measuring ambient light level
;   with CdS photocell wired from LogoChip port A1 to +5V
;   and 1K resistor wired from A1 to GND.
;
;   When light level suddenly becomes dimmer, trigger audio playback
;   using Radio Shack 276-1323 20-second recording modules
;   with play buttons wired to LogoChip ports C6 and C7.
;   Play buttons are active low.

;   Port assignments for the photocell and audio units
constants [
        [cds-port porta] [cds-ddr porta-ddr] [cds-bit 1]
        [squawk-port portc] [squawk-ddr portc-ddr]
                [squawk-left-bit 6] [squawk-right-bit 7]
]

;   Array for averaging brightness
global [array0 array1 array2 array3 array4 array5 array6 array7 array-index]
constants [
        [array-base 2]
        [array-len 8]
]

;   Current brightness, sum of recent brightness, average recent brightness
global [bright sum-bright avg-bright]
;   Calculated brightness values that indicate dimming
global [threshold-shady threshold-dark]

;   At powerup, run the main program.
to powerup
        startup
end

;   At startup, clear the array storage space, initialize some
;   global variables, and configure the I/O ports.
to startup
        init-array
        init-vars
        init-squawk-port
        init-cds-port

        prs "starting
        watch-brightness
end

;   Loop forever, taking samples and watching for dimming.
global [already-shady already-dark]
to watch-brightness
        loop [
                ;   Calculate what fractions of previous brightness
                ;   constitute being dim
                calc-thresholds

                ;   Get current brightness
                read-bright

                ;   The following logic for different brightness conditions
                ;   is carefully arranged to make a successful test exclude
                ;   success on subsequent tests.  I would have preferred to
                ;   write this using
                ;
                ;   if  [ block 1 ]
                ;   elseif  [ block 2 ]
                ;   elseif  [ block 3 ]
                ;
                ;   but LogoChip Logo doesn't support that, and I got cranky
                ;   nesting the conditional blocks three deep using the syntax
                ;   that _is_ supported.
                ;
                ;   Caveat maintainer.

                ;   If we're getting brighter,
                if bright > avg-bright [
                        ;   Start paying attention to getting dimmer again
                        setalready-dark 0
                        setalready-shady 0
                ]

                ;   If we're significantly darker than before,
                if bright < threshold-dark [
                        ;   And we haven't already done something about it,
                        if not already-dark [
                                ;   Then cause an event
                                dim-a-lot-event

                                ;   And remember that we're already dark
                                ;   and don't need to trigger another event.
                                setalready-dark 1
                                setalready-shady 1
                        ]
                ]

                ;   If we're a little darker than before,
                if bright < threshold-shady [
                        ;   And we haven't already done something about it,
                        if not already-shady [
                                ;   Then cause an event
                                dim-a-little-event

                                ;   And remember that we're already shady
                                ;   and don't need to trigger another event.
                                setalready-shady 1
                        ]
                ]
        ]
end

;   Event routine for when slight dimming is detected
to dim-a-little-event
        prs "|dimming a little|

        ;   Play the message from the right speaker.
        squawk squawk-right-bit

        ;   Give it a couple of seconds to finish.
        wait 20
end

;   Event routine for when significant dimming is detected
to dim-a-lot-event
        prs "|dimming a lot|

        ;   Play the message from the left speaker.
        squawk squawk-left-bit

        ;   Give it a couple of seconds to finish.
        wait 20
end

;   Clear the array.
to init-array
        setarray-index 0
        repeat array-len [
                setglobal (array-base + array-index) 0
                setarray-index (array-index + 1) % array-len
        ]
end

;   Initialize global variables.
to init-vars
        setsum-bright 0

        setalready-shady 0
        setalready-dark 0
end

;   Configure the audio trigger I/O port.
to init-squawk-port
        ;   Set left and right triggers off (active low, so set high)
        setbit squawk-left-bit squawk-port
        setbit squawk-right-bit squawk-port

        ;   Set left and right triggers as outputs
        clearbit squawk-left-bit squawk-ddr
        clearbit squawk-right-bit squawk-ddr
end

;   Configure the photocell I/O port.
to init-cds-port
        ;   Set photocell port as input
        setbit cds-bit cds-ddr

        ;   Give time for the operator to get their hand out of the way
        ;   and find out how bright the room can be
        repeat 10 [
                ;   Read the current brightness and store rolling average
                read-bright
                ;prs "average
                ;print avg-bright
        ]
        ;prs "|final average|
        ;print avg-bright
end

;   Trigger the external playback modules
;   Parameter: which module to trigger
to squawk :squawk-bit
        ;   Trigger it (active low, so set low)
        clearbit :squawk-bit squawk-port

        ;   Wait a smidge to be sure it registers
        wait 1

        ;   Clear the trigger (active low, so set high)
        setbit :squawk-bit squawk-port
end

;   Read the brightness and work it into a rolling average.
;   Uses a ring buffer to compute the rolling average.  If you know what
;   that means, there's not much I can teach you about LogoChip Logo.
to read-bright
        ;   Read current brightness
        setbright read-ad cds-bit
        ;prs "|current brightness|
        ;print bright

        ;   Roll off oldest value from rolling average and add current
        ;   Parentheses around first two operands are necessary--
        ;   returns random result without
        setsum-bright (sum-bright - global (array-base + array-index)) + bright

        ;   Save current brightness and advance history pointer
        setglobal (array-base + array-index) bright
        setarray-index (array-index + 1) % array-len

        ;   Calculate recent average brightness, rounding the fraction
        setavg-bright (sum-bright + (array-len / 2)) / array-len

        ;   A/D converter seems to require .2 sec between readings
        wait 2
end

;   Calculate thresholds of dimming based on recent average brightness.
;   Multiply then divide because fractions become 0 in integer arithmetic.
to calc-thresholds
        setthreshold-shady (9 * avg-bright) / 10
        ;prs "|shady threshold|
        ;print threshold-shady
        setthreshold-dark (5 * avg-bright) / 10
end