Gas station without pumps

2017 December 18

EKG without amplifier

Filed under: Circuits course,Data acquisition — gasstationwithoutpumps @ 18:24
Tags: , , , ,

I have done a lot of EKG projects on this blog, mostly for the Applied Electronics course, where an EKG amplifier is Lab 12, but some just for fun. Today I decided to see whether one could do an EKG with just the Teensy LC board or just an Analog Discovery 2 USB oscilloscope.

The project was partly inspired by the Digilent post DIY ECG using a Analog Discovery 2 and LabVIEW, which I saw the title for and assumed that they were using just the USB oscilloscope.  It turns out that wasn’t what they meant—it is just a simple 6-op-amp EKG amplifier looked at with the USB oscilloscope.

The setup I tried was about as simple as you can get—I put on three electrodes wired up as Lead I (see earlier post for this configuration), connected the body electrode to ground, and the other two electrodes to the plus and minus leads of channel 1 of the Analog Discovery 2.

The signal I got was quite small (about 1mV) and buried in 60Hz noise:

The raw signal from the oscilloscope, sampling at 1200 Hz, shows some spiking from the pulse, but a lot of noise. The big R spike is only about 3 LSB, so quantization noise is a problem.

I ran the recording through a digital filter to bandpass filter it to 0.1Hz–100Hz and put in a notch from 58Hz to 62Hz. The 100Hz low-pass had the effect of averaging out the noise, producing a signal with much finer resolution than the raw ADC values:

After filtering, the EKG signal is fairly clear. I don’t recommend trying to use only a couple of the lower-order bits of an ADC, but it is surprising how much information can be recovered by the filter.

I also tried using a Teensy LC board running PteroDAQ, using the A10–A11 differential channel. I had to bias my body between 0V and 3.3V, so I used a pair of 120kΩ resistors (one to GND, one to 3.3V) to connect to the body electrode.

Once again the raw signal was not great:

The signal had less noise than the signal to the Analog Discovery 2, but the signal was smaller also, negating the value of the finer steps of the ADC on the Teensy LC.

Once again, digital filtering restored the signal:

The signal-to-noise ratio here looks a little worse than for the Analog Discovery 2, despite the raw signal looking cleaner.

I managed to get a cleaner signal for the Analog Discovery 2 by turning off the surge protector, so that there was no 60Hz current anywhere nearby. The results after filtering were no better (and possibly worse) than from the signal with the 60Hz interference, so I did not bother plotting them for this post.

My conclusion is that it is possible to get EKG signals without adding an amplifier, but you can only see the signal clearly if you do some filtering.  I’ll have to decide whether to recommend to students that they record signals directly from the EKG electrodes to get an idea what their amplifiers have to work with.


2017 November 17

Tape sensors

Filed under: Robotics — gasstationwithoutpumps @ 15:06
Tags: , , , ,

One of the requirements of the robot for Mechatronics is that it have optical sensors on the bottom to detect black tape on a white background, for detecting the edges of the field, alignment marks for the Ren-ship target, and other marks on the field that seem to be there just to be a nuisance and make the state-machine design harder.

We were issued a number of TCRT5000L reflective sensors, which consist of an IR emitter and a phototransistor in a plastic package that is optimized for a surface 2mm away.  Although the sensors are designed to snap into PC boards and could probably be snapped into carefully sized holes in MDF, I’ll be mounting them on perfboards, which will be screwed onto the top of the baseplate of my robot, with rectangular holes in the MDF for the sensor to poke through.  They’ll barely poke through (6mm high — 5mm MDF), which means they’ll be about 7mm from the floor.  At that distance, the collector current is about half what it would be at the optimum distance.  The MDF provides some extra shrouding from stray light from the sides, which should help with detection.

I’m planning to turn the IR emitters on only when I need to read the sensors, to save power and to allow synchronous detection of reflectance (looking at the difference in light levels between the IR emitter being on or off).  By keeping the duty cycle below 50%, I can run the IR emitters up to 50mA, though I may not need them to be that bright.

If I switch on 5 IR emitters at once, at 50mA each, I’ll be  using 250mA, which is the limit for what I could get from the Teensy 3.2 3.3V regulator (rated for 250mA, though that’s a thermal limit, so 500mA may be available for low duty cycle) and far exceeds the 100mA limit for Teensy LC or Teensy 3.1 boards.  I will be using a 5V regulator to power the Teensy boards, so I could use the 5V supply to power the IR emitters also.

If I use only 10mA per IR emitter, I only need 50mA total and so could power off of either 3.3V or 5V.

For 50mA at 5V, I’d need a current-limiting resistor of ≥(5V–1.2V)/50mA=76Ω, so an 82Ω resistor for 46–48mA would work.  For 10mA at 5V, I’d need ≥(5V–1.1V)/10mA=390Ω, and for 10mA at 3.3V, I’d need ≥(3.3V–1.1V)/10mA=220Ω.

I have a couple of choices for wiring up the sensors:

There are 3 wires to each sensor board, but only the current output is unique to the board—the IR emitter connections can be shared among all sensors.

Low-side switching only requires an nFET, but the power connection for the IR emitter is limited to 3.3V. High-side switching keeps the 3.3V power line from being routed near the motors, but requires a 5v-powered inverter to get a sufficiently large voltage to shut off the pFET.

The expected current from a white background @7mm is about 400µA for 10mA input or 2mA for 50mA input, assuming VCE is in the active region (above about 0.5V).  If I’m looking for a 1V swing between dark and light, I’ll want about 2.5kΩ for the sense resistor for a 10mA input and 500Ω for a 50mA input.

I did a couple of tests with the TCRT5000L using the low-side switching configuration, with 3.3V and a 220Ω current-limiting resistor.  I was doing the tests in a well-lit room (my breakfast room on a sunny day, but without direct sunlight in the room), so the background light is probably brighter than the robot will ever have to deal with.  I used one of the wheels from the MockRobot to be the target, since I could put a screw through the axle hole to get a more-or-less consistent spacing from the sensor.  I adjusted the nut so that the spacing was about 7mm from the sensor, but the angle was only controlled by eyeballing the levelness of the target, so probably varied by ±10°. I did not have any of the black tape that was used on the fields, so I substituted black electrical tape, which I think may be slightly more reflective.

I initially tried 2.7kΩ as the sense resistor, but after seeing the voltage range for that, I upped it to 5.1kΩ.

With 5.1kΩ, the voltages when illuminated are very different between black and white—a simple digital input would suffice.

The currents can be seen to be about the same, independent of the sense resistor, with the white MDF giving about 10 times current of the black electrical tape. The signal from background illumination is insignificant, though that might not be true if the IR beacon is lighting up the field.

It looks like 10mA (measured as 9.65mA) is more than enough light for the sensors to tell black from white, and that the signal is strong enough that I don’t really need analog input or synchronous sensing for the tape sensors.  If I get really worried about the digital signal in worst-case conditions (like too large a distance), I could increase the size of the sense resistor further.  With a 22kΩ sense resistor, I get a very clean separation between white and black even at 1cm.

I have to decide whether to pulse the IR emitters and wait at least 100µs before reading all the sensors, or just to leave them on all the time (at a cost of 10mA per tape sensor). If they are on all the time, I could use the 5V supply (with a 390Ω current-limiting resistor instead of a 220Ω one), and not worry about overloading the Teensy regulator. This could also simplify wiring, as the 5V regulator could be on the power board on the first level and the battery wiring would be limited to the first level.

The Teensy 3.1/3.2 digital pins are 5V-tolerant, so I could even connect the phototransistor collectors to 5V and put the multiplexer on the first level using 5V power. I could then put the sense resistors on the tape-sensor boards and have three wires for each board: 5V, GND, and WHITE.  I could use 3-pin male headers and standard Futaba servo cables to do the wiring.

I ordered a set of servo cables through Amazon, but they are not expected to arrive for another 2–6 weeks, so aren’t going to do me much good.)  I can make my own, but I’ve been having trouble lately with intermittent contacts from the crimp-on connectors and have taken to wicking tiny amounts of solder into the crimp, which adds a lot of time to making the cables.

With the multiplexer on the first layer, the only cabling from the tape sensors to higher levels would be 5V, Gnd, 3 select signals, and the (now digital) signal for sensing the tape. The motors are also on the bottom level, and they would additionally need 2 wires for controlling each motor and 2 wires per motor for feedback from the Hall-effect encoders. This makes the total wire bundle from the bottom level up to higher levels be only 14 wires (5V, Gnd, 4 for tape sensors, 2×4 for motors), with none of the wires having high-current switching.  The only high current wires are the 5V and Gnd wires, which may be feeding servo motors on higher levels—I may want a separate power wire from one of the switching regulators for powering servo motors on the higher levels, though.

The Teensy LC is not 5V-tolerant, so if I used that for the main controller board, I would need to communicate a 3.3V power line as well for the phototransistors and the motor encoders.  I think that I’ll simply declare that the main controller needs to be 5V-tolerant for digital inputs.

[Update 2017 Nov 18: I soldered up one of the TCRT5000L circuits, so that I could do a little more testing and make sure that I had a layout that worked.  It turned out that 22kΩ for the sense resistor was too large—at some distances the electrical tape reflected enough light to get above the 1.15V which is the guaranteed max VIL and maybe even enough to get to switch to high. I took out the 22kΩ and used a 10kΩ, and the problem with black reflecting too much light went away, but white still produced a very strong signal. I should be able to detect the white board reliably with just digital inputs out to about 1.4cm, much more than the 0.8cm clearance.

2017 November 15

Progress report on mechatronics

Filed under: Robotics — gasstationwithoutpumps @ 19:27
Tags: , ,

I’m falling behind in the mechatronics course—I still don’t have a complete design for the robot, and I’ve built nothing so far except the cat-toy ball track, which is not complete yet—I need to know how much of it to cut away for the ball launcher(s), which I’ve not designed.  I also have the digital beacon detector done, though I think I want to retweak the code for it, as I messed it up trying to get more sensitivity at the distance competition.

I spent yesterday struggling with SolidWorks.  I’m getting better at it, but it is still a terribly complicated, unintuitive interface.  Even trivial things like creating a sphere as a model ping-pong ball took a long time to figure out (I had to Google it, and even then it took me a long time to realize that “centerline” was a special tool, not just a line through the center.  My biggest accomplishment in SolidWorks so far is modeling the helical cat-toy ball track—I’ll have to get a picture of that model to put on the blog.

I did get most of the first layer of MDF designed yesterday, with the motor mounts, the wheel wells, the tape-sensor holes, the battery holder (MDF and velcro), and the M10 ball-tip set screws (to use as skids) all modeled.  I even got one support board for positioning the next layer done, though I’ll probably have to adjust it a bit, as I changed my mind last night about what bumper switches to get.  Instead of spending $3–5 a switch for gold contacts (which is the “right” way to handle low-current switching), I followed the lead of one of the students and am getting super cheap switches from Amazon, which are $7 for 10 switches.  These are standard 5A switches and probably get unreliable with currents below 100mA, though I’ll be using them with 1mA or less.  They are also tiny (specs from the Amazon page):

  • Overall Size : 20 x 6.5 x 13.5mm / 0.79″ x 0.26″ x 0.53″ (L*W*H)
  • Mounting Hole Dia. : 2mm / 0.08″;Mounting Hole Spacing : 9.5mm / 0.37″;Pin Pitch : 7.2 x 9mm / 0.28″ x 0.35″
  • Lever Arm Size : 17.5 x 4mm / 0.69″ x 0.16″ (L*W);Roller Size : 5 x 3mm / 0.2″ x 0.12″ (D*T)

The small size means that the second level will have to be slightly higher to put the bumpers at the right height.

Before I cut the first-layer board, I want to add the rest of the spacer boards between the first and second layer—one of which will have my volt/ammeter and power barrel jack (so I need to measure those and design the panel for them).

I also have to decide how I’m going to lock the boards together.  I don’t want to glue things (messy and hard to disassemble), so I’ll probably clamp everything together with threaded rods.  I’ll need to get the threaded rods and figure out where to put the holes for them so as not to interfere on any level—avoiding the cat-toy ball track will be the hardest, as it takes up most of the second level. Although most of my robot will be using metric parts, I’ll probably go with threaded rod from the hardware store, which will most likely be ¼” rods with 20 threads per inch, as that seems to be the cheapest (at 50¢–$1 a foot).  I think I’ll need 4 pieces, a little under 11″ long each (so that the top of the rod is at 11″ but the bottom doesn’t touch the floor).

I need to laser cut a small test piece with different hole sizes, to see how much increase in diameter there is from the laser cutting.  Most of my holes can be a little loose without problems, but the set screws need to screw into the MDF (unless I get some M10 nuts and put them on either side of the MDF, which might be a better solution anyway).

Today I was going to build tape sensors (soldering the TCRT5000 reflective sensors and current-limiting resistor onto protoboards that have screw holes drilled for mounting), but I’ve not done any hardware work so far today.  Last night I did order the bigger (100mH) inductors for the track-wire sensor, plus a few smaller shielded inductors, in case I decide to add another LC resonator to the sensor, to increase noise rejection, but I forgot to order an 8:1 analog mux, which I think I’ll need for extending the number of pins on the Teensy.  Oh well, another $3–4 in shipping costs and another few days delay.

I’ve spent most of today working on porting the Events and Services Framework to the Teensyduino environment.  I’ve got it all compiling and I’ve got event checkers working, but I haven’t checked the timers or other layers of services.  It turns out that the test harnesses built into the code have not been maintained, and some wouldn’t run (or even compile) even on the Uno32, because the code they supposedly test has been changed and no longer has the entry points they rely on (ES_Timers is one example).

The ES_Framework code is also not very modular, despite being broken up into many files—almost everything is intertwined to the point where you need it all before anything can compile.  Luckily, most of it has very little dependence on the specific processor, so I was able to port it without trouble.  One of the biggest problems was that the Teensyduino environment does not support printf, and the Serial.print() routine is C++, not C.  I added a few C wrappers for different flavors of Serial.print() and converted all the printf statements to a series of Serial_print_… calls.

I’ve not still figured out the best way to handle the analog-to-digital conversion.  The Pic32 processor used in the Uno32 boards for the class have a “scan” mode where the hardware handles scanning the selected analog channels, just doing an interrupt after all the channels have been scanned.  The Kinetis processors on the Teensy boards do not have that feature, so I have several options:

  • doing conversions in event detectors or services that need the values.  This will make the individual detectors slower, but no time will be wasted doing unused conversions. It would also make it easy for users to extend the number of analog pins with an external MUX, as the code for doing the analog conversions is not buried inside the system, but in the user-level code.  The disadvantage is that the code will need to busy-wait for each conversion, as the result is needed at the point in the code where it is requested.  I could just use the Teensyduino analogRead(), which already provides support for setting the resolution and averaging levels.  Then there is no need to port the AD.c file.
  • do a block of conversions just before calling all the user-defined event detectors.  This will put a largish delay before the event detectors, but several detectors or services can look at the value with needing another conversion. Currently, the event detector loop with just a trivial DummyEventChecker (that reports an event every 100,000 calls and toggles the on-board LED) takes about 3.34µs on a 72MHz Teensy 3.1, but doing 6–8 conversions would add 8–500µs, depending on how much hardware averaging I decide to do (which the user should be given access to control).  This technique is probably the closest to letting me duplicate the existing interface, which is designed around the Pic32 scan.
  • do a start-conversion and interrupt for each conversion.  If I do little hardware averaging, the overhead of the interrupt processing is large and nothing is gained, but if I opt for 32× averaging then interrupts have a big advantage over blocking code that busy waits for the conversions.

Currently, I’m leaning towards just using the analogRead() code, discarding all the Pic32-specific AD code.  I still need to decide whether to build in a battery-level check that shuts down the system on a drained battery.  Perhaps the cleanest way to do this would be to build a separate event checker that samples the battery voltage about every millisecond and low-pass filters it (rather than at 9345Hz/number of pins, the way the Uno32 code does).  (Sampling about every millisecond could be done just by watching the clock in the event checker and taking a new sample every time that millis() changed.)  Having a separate checker in a separate file, rather than intertwined with BOARD.c, AD.c , and roach.c would be much cleaner. After I’ve gotten all the basic functions working, I’ll think about dedicating a pin (perhaps A0, which has the fewest other functions) to battery-voltage monitoring.

I’m not sure how to ensure that all the external devices (servo motors, gear motors, … ) are properly turned off in BOARD_End(), before sleeping or halting the processor.  The Uno32 version of BOARD_End() doesn’t seem to do this either—in fact, it keeps the ADC and the serial port on, and just turns off most interrupts and sets pins to be digital inputs, not doing anything about the external peripherals that are the power-hungry ones.

2017 November 8

Starting to port the Events and Services Framework to Teensy boards

Filed under: Uncategorized — gasstationwithoutpumps @ 23:23
Tags: , , ,

Because I want to work at home with boards that I own, I need to port the Events and Services framework used in the Mechatronics class to the Teensy LC or Teensy 3.1 board.  The first thing to do is to identify what resources are used by the Teensyduino framework, and so inaccessible to me (except through their API).

The ES framework itself has only one interrupt routine, in ES_Timers.c, which runs on a millisecond tick, updating FreeRunningTimer and checking to see whether any of the ES_Timers have just timed out. While I would have loved to do this with the SysTick timer on the Teensy boards, Teensyduino uses that its own millisecond timer (accessible through millis()).  So I’ll probably have to use the IntervalTimer interface, which will use up one of the PIT (programmable interrupt timer resources).

Because I’ll be doing hardware pwm on selected pins, not software pwm, I don’t need to port the pwm code from the Uno32 library.  I will need timer resources for hardware pwm, which means using pins that have pwm support.  Different pins use different timers for the pwm, and the table at provides the mapping:

Teensy 3.2
Teensy 3.1
FTM0 5, 6, 9, 10, 20, 21, 22, 23 488.28 Hz
FTM1 3, 4 488.28 Hz
FTM2 25, 32 488.28 Hz
Teensy LC FTM0 6, 9, 10, 20, 22, 23 488.28 Hz
FTM1 16, 17 488.28 Hz
FTM2 3, 4 488.28 Hz

(They provide the mapping for other Teensy boards also, but I will only use LC and 3.1/3.2 boards on this project.) If I just use two PWM channels, then pins 3 and 4 would be a good choice on either chip, as few other uses conflict with those pins and they share a timer.  If I need more than 2 PWM channels, then pins 6, 9, 10, 20, 22, and 23 share FTM0 on both chips. Three of those channels are also A-to-D channels and pin 20 is SCK1 (the second SPI interface clock).  I’m planning to use pints 11, 12, and 13 for the SPI interface, plus one other digital pin for the chip select, so the conflicts on the PWM pins are probably irrelevant.

I don’t like the default PWM frequency of 488.28 Hz, though, and so will be changing the PWM resolution and frequency to get a PWM frequency above the audible range (the MAX14870 H-bridges had no trouble handling up to 50kHz).  Using an 10-bit resolution with a clock speed of 48MHz (Teensy LC) would give me a PWM frequency of 46875Hz and  with a clock speed of 72MHz (Teensy 3.1) 35156.25Hz (the code does some prescaling).  These look like good frequencies to request.

The code provided for the Uno supports RC servos with another timer.  In the Teensyduino library there are two different servo implementations: Servo and PWMServo.  PWMServo uses the same PWM hardware that the pwm library uses, but at a 50Hz PWM frequency.  If I use that library, it will be important to cluster the servo pins on to one of the FTM timers and the pwm pins onto a different timer.  The Servo library uses the LPTM timer on the Teensy LC and the PDB timer on the Teensy 3.1/3.2, which does not conflict with other uses, but the servo timing is subject to glitching, especially if interrupts are ever disabled in the code.

The Uno32 board is set up to read analog-to-digital values continuously so that reading the data can be a non-blocking operation that just grabs the latest value without waiting for a new conversion.  For my first version of the port, I’ll just use analogRead to read pins, but if that turns out to be too slow (which it might), I’ll change to using the analog reading used by PteroDAQ. One oddity of the ES framework is that the battery-check code is built into the analog-to-digital conversion code, and the processor put to sleep if the battery is low.  I suppose this was done so that filtering of the battery voltage could be done in the interrupt routine that samples all the ADC channels.  It seems like a worthwhile thing to shut everything down if the battery gets too low, so I might decide  to do something like theADC library.  The Teensy boards don’t have an interface for cycling through the channels the way the Uno32 appears to, so I would probably have to set up a rather different interface for this.  This looks like the biggest difficulty in porting the framework—it might be better to set up a battery monitor that is not embedded so deeply in the code, perhaps having a battery-check event checker that is automatically polled.

The provided timers.c package gives access to another set of millisecond timers, which can be polled.  This library does not seem very useful—if I want to know the time, I can call millis() and if I want to poll whether enough time has elapsed, I can compare millis() to a computed stop time.  It does not seem worthwhile to use up another timer just for millisecond resolution.

I’m not planning to use a stepper motor, so I won’t port the Stepper routines (which we had to modify as a homework exercise).  If I were to port these routines, I’d probably use up another IntervalTimer (which exhausts them for the Teensy LC).

The serial.c code uses a UART interrupt to send or receive over the USB port, but the Teensyduino enviroment includes Serial, so all I would need to do is to

#define printf Serial.printf

and there is no need to port serial.

So far, it looks like the partial port that I’m planning (porting the ES framework but not the peripherals) looks very straightforward, other than the battery voltage monitor.  I might skip that in the first port, and add it back in later.

2016 September 27

Teensy 3.5 & 3.6 Kickstarter

Filed under: Uncategorized — gasstationwithoutpumps @ 16:59
Tags: , , ,

As many of the followers of my blog know, the Teensy 3.1 and Teensy LC have been my favorite microcontroller boards for the past couple of years.  The Teensy 3.1 has since been replaced by the slightly better Teensy 3.2, which has a better voltage regulator but is otherwise pretty much the same as the 3.1.  I’ve been using the Teensy LC with PteroDAQ software for my electronics course.

I’ve just noticed that PJRC has a Kickstarter campaign for a new set of boards the Teensy 3.5 and 3.6.  These will be much more powerful ARM processors (120MHz and 180MHz Cortex M4 processors with floating-point units, so at least 2.5 times faster than the Teensy 3.2, more if floating-point is used much).  The form factor is similar to before, but the boards are longer, taking up 24 rows of a breadboard, instead of just 14.  The extra board space is mainly to provide more I/O, but there is also a MicroSD card slot.

The designer is still dedicated to making the Teensy boards run in the Arduino environment, and the breadboard-friendly layout is very good for experimenting.

PJRC is positioning the new boards between the old Teensy boards and the Linux-based boards like the Raspberry Pi boards. The new Teensy boards will have a lot of raw power, but not an operating system, though I suspect that people outside PJRC will try porting one of the small real-time operating systems to the board.

The new boards are a bit pricey compared to the Teensy LC ($23–28 instead of under $12 for the Teensy LC), but still reasonable for what they provide.  PJRC also has a history of providing good software for their boards.

I probably need to get both a Teensy 3.5 and a 3.6 to port PteroDAQ to them—that looks like a $50 purchase. If the boards and the software are available in time for me do development on PteroDAQ by December, I might get it done—any later than that and I’ll have no time, as I have a very heavy teaching and service load for Winter quarter.

I suspect that the new Teensyduino software will need a newer version of the Arduino development environment, which in turn would require a newer version of the Mac operating system (my laptop is still running 10.6.8), which in turn probably means a new laptop.

I’m waiting to see if Apple releases a new, usable MacBook Pro in October, so there is a bit of built-in delay in the whole process. I’m not impressed with their recent design choices for iPhones and MacBook Air—I need connections to my laptop—so there is a strong possibility that I may be having to leave the Macintosh family of products after having been a loyal user since 1984 (that’s 32 years now).

Update 2016 Sep 27: I just watched the Kickstarter video.  They used the Karplus-Strong algorithm as a demo.  Of course, that demo could have been done on a Z80 chip from 1976 (though not easily—the sampling rate suffered a bit to run 4 strings on the Z80, and only 8-bit DACs were affordable in those days).  It would have been more instructive to do an FM synthesis algorithm, which takes a lot more processor power than Karplus-Strong.

Next Page »

Create a free website or blog at

%d bloggers like this: