Neil's Log Book https://nrqm.ca What could possibly go wrong? Sat, 08 Feb 2014 23:16:55 +0000 en-US hourly 1 https://wordpress.org/?v=5.4.1 Strobe Guitar Tuner r2 Design Changes https://nrqm.ca/2014/02/strobe-guitar-tuner-r2/ Wed, 05 Feb 2014 07:14:14 +0000 https://nrqm.ca/?p=991 Circuit board rendered by oshpark.com.

Circuit board rendered by OSH Park.

I’ve learned a bunch about making circuit boards at work recently, so I decided to re-do the ol’ strobe guitar tuner project from 3 or 4 years ago.  The original still works… sort of.  I have to power it from a 3x AA battery holder that’s clipped to the power terminals with alligator clips.  It doesn’t tune the low E string properly for some reason.  The input’s inflexible, and it’s hard to reprogram.

The hardware has been updated in the following ways:

  • I’ve learnt how to use KiCAD for circuit design.  It’s a lovely open source EDA tool that handles schematic design, layout, and automated trace routing.  ExpressPCB was okay for the original tuner, but this board is a bit more complicated, complicated enough that laying the circuit out manually would be difficult, tedious, and error prone.  Plus I need to output gerber files, because…
  • … I’m going to get the PCBs manufactured instead of etching them manually.  At work I needed 24 little boards manufactured for a project and went with OSH Park.  I was very happy with the outcome OSH Park is a great batch service, they can make two-layer boards with silkscreen and soldermask for a reasonable price in low volumes.  The main downside is their lead time is around a month.  I also considered circuits.io, which seems like a really cool idea, but their design tools seem rudimentary (or maybe I’m just not accustomed to them), they use OSH Park on the back end so they’re more expensive, and they don’t allow full control over the board’s source files (that is, you can’t download them in gerber format).
  • The battery supply has been changed from a coin cell to 2x AAA batteries.  The battery holder will mount on the back of the board.  I’m a little concerned that it won’t be as comfortable to hold as the old version, we’ll see.  Battery life is also suspect, I figure a pair of AAAs should last something over 10 hours.  Is that long enough?  Probably, right?  It’s only going to be on for a few minutes at a time and I can program in an automatic shut-down if it gets left on.
  • There’s a real power switch that will disconnect the battery instead of putting the MCU to sleep.
  • There’s a switching regulator now.  I added the regulator, configured to output around 2 V, so that all the LEDs are delivered a constant current over the lifetime of the batteries.  Without the regulator the LEDs get dimmer as the batteries drain.  I chose a switching regulator instead of a linear regulator mainly because it’s cool and I’ve never used a switching regulator before.  Also it has a very low dropout (about 0.05 V) and will be more efficient for most of the battery’s lifetime.  Fun fact: the first regulator I chose was the only cheap 2.0 V fixed-output switching regulator on Digikey, but I failed to notice at first that it’s 1.5 mm long and 1 mm wide.  It fits six surface mount pads in that area, and has no leads.  I’m not soldering that by hand, but I applaud its existence.  Well played, Texas Instruments.
  • There’s a 6-pin PDI port for programming the microcontroller in the circuit.  As you can see the MCU is a TQFP chip that’s soldered directly to the board, so a programming port is necessary.  It would be cool to get a USB-capable MCU so that tunings can be set from a host computer without reprogramming the board, but that’s a feature for the 2018 version.
  • I spent a long time trying to figure out the human-device interface.  My original tuner just had a 6-way switch to select one of the six notes in the standard guitar tuning.  I wanted the interface to be flexible enough to support multiple tunings–not that I’m a competent enough guitar player to need multiple tunings, but it seems like a good idea nonetheless.  I considered two rows of LEDS, one to indicate the current note and one to indicated the selected tuning.  I also considered a dual 7-segment LED display to display the selected note in scientific pitch notation (e.g. E2, A2, G3, D3, B3, E4).  Finally I settled on a single 7-segment display, which I thought was pretty clever until I went back and looked at the project my original tuner is based on and discovered that’s what they’d done in the first place.  The user controls the tuner with two buttons to navigate up and down, and one button to switch mode between tuning select and note select.  Again, how comfortable will be to operate the switches one-handed while holding the tuner without risking electrostatic discharge in the components next door is an open question.
  • The MCU is an ATxmega8E5.  I’m coming around to the xmega line, although it’s kind of caught in the middle between ARM and the old megas.  The xmega library is more sensible than the mega’s library, the xmega has more features, and it costs about the same as an equivalent mega.  Originally I intended to use an ATSAMD20E14A, one of Atmel’s newish ARM Cortex-M0+ chips.  They look like nice MCUs and cost about the same as an equivalent mega/xmega.  One of the reasons I started this project was to get some experience with ARM.  Unfortunately that chip (and other ARM chips I looked at) has a maximum current output of 3 mA on I/O pins when powered with 2 V, so it’s really not suitable for an application that boils down to turning a bunch of 10 to 20 mA LEDs on and off.  The xmegas allow 25 mA per pin.

Next step: reviewing and tweaking the PCB design and ordering a few boards.  They should be here in a month or so.

]]>
Robotic Monochord Guitar Version 1.0 https://nrqm.ca/2013/09/robotic-monochord-guitar-version-1-0/ Sun, 29 Sep 2013 02:51:17 +0000 https://nrqm.ca/?p=967 More like version 0.1, every part of it was bad in some way.  We did robotic self-tuning monochords—single-string musical instruments—last spring in the mechatronics class.  The students did pretty well.

Most of their robots were designed along similar lines: they had a servo with a pick to pluck the string, an electric guitar pickup from which the robot read the string’s frequency, and a stepper motor to spin a machine head to adjust the string’s tension (and thereby change the frequency).  The design had some issues that the students didn’t have time to fix before they had to move on to their next projects.  We found that the biggest problem was that the tension controls weren’t responsive.  The machine heads are made more for precision than speed—with a guitar you have to tune a string precisely, but you shouldn’t have to do it very often so it doesn’t matter if it’s slow.  One team adjusted the tension using a linear actuator that stretched the string by moving a bar back and forth, which was a novel idea but which also suffered from unresponsiveness since they necessarily used a lead screw as a linear actuator.

I figure a robot should be inherently precise compared to a human, so machine heads are the wrong tool for the job.  We ought to be able to find a speedier way of adjusting the string frequency.  Instead of adjusting the tension I wanted to try adjusting the string length like you do with your fingers in most real stringed instruments.

First try at a guitarbot.

First try at a guitarbot.

For my first try I printed out a herringbone rack and pinion and screwed it to a board with some countersunk screws.  That was the most successful part of the project: the pinion, mounted to a stepper motor, moved smoothly back and forth along the rack in spite of the screws interrupting the rack teeth.

The stepper had two roller bearings functioning as wheels holding it up in back, and it was supported in front by the rack.  I printed a wheel to apply pressure to the string (simulating the finger/fret), and a v-shaped support to raise the wheel above the pinion and to centre it.  Originally I had the wheel mounted to just one of the motor’s screw holes, but since it was off-centre the pressure from the string pushed the motor on its side.  The wheel rolled smoothly along the string, so that was cool too.  The string was held by a couple of eye bolts with grooves cut in them to keep the string in place (replacing the guitar’s nut and bridge), and was connected to a machine head for easy tensioning.  The stepper was controlled by an Arduino with two buttons to make the motor turn back and forth.

The things that sucked:

  • I sanded a groove into the wood platform to keep the wheels straight, but it was too shallow and didn’t do its job
  • It was super-hard to get the printed rack straight, and it didn’t line up with the string all the way along the robot
  • The robot was way too short and didn’t produce an interesting range of sounds.  The rack was like 18″ long, and less than half of that was usable since the string just damps out if it’s too short (like plucking the string that leads from the machine head to the nut on a real guitar)
  • The stepper had too much inertia and its centre of mass was too far back.  I was hoping that between the herringbone teeth on the rack and pinion, the wheel groove, and the downward force from the string, the motor would move relatively smoothly.  Unfortunately it couldn’t move at high speed accurately and stably.  At a certain point on the rack it would just twist itself off.
  • In order to adjust the pressure of the wheel on the string, I needed to de-string the guitar, screw the eye bolts in or out, and re-string the guitar
  • The plastic wheel damped the string a bit compared to a metal fret

I didn’t bother installing a plucking system or a frequency sensor.  Instead I started work on version 2, which uses a Makerslide linear bearing and a more traditional belt-and-pully system for moving the carriage back and forth, kind of like in the MechBass video that I linked to above.  I like the idea of having the string “fingered” by a wheel instead of fingers à la MechBass, it ought to produce a neat slide-guitar effect and will also make it very easy to add vibrato to a note.  Anyway, version 2 is underway and I think it will solve most or all of the problems from version 1 that I listed above.  Alas, I didn’t order enough parts and our 3D printer broke, so as of this writing development is paused.

]]>
AVR Code for the MS5541C Pressure Sensor https://nrqm.ca/2013/01/avr-code-for-the-ms5541c-pressure-sensor/ Wed, 23 Jan 2013 00:22:56 +0000 https://nrqm.ca/?p=903 I originally wrote code for the MS5541C pressure sensor using bit banging, and described the result of my investigation in the previous log entry.  At the end I mentioned that the sensor’s weird digital interface is kind of like SPI, and looks SPI-compatible, with several differences that could be worked around.  The most notable difference was that reading and writing data happen out of phase with respect to the serial clock edge. It wound up being a little squirrellier than that, but it worked out.  Below is some code for accessing the MS5541C with SPI. It runs on a Seeeduino Mega (which is compatible with the Arduino Mega and uses the ATmega1280 microcontroller), but I’ve eschewed the Arduino libraries for the sake of more control (and, for the ol’ bit-banging, better timing resolution). Some of the code, particularly the SPI stuff, could be replaced with Arduino library calls.

Let’s start, as always, with some definitions:

#define SPI_DDR DDRB	// DDR of SPI port
#define SPI_PORT PORTB	// SPI port
#define SPI_MOSI PB2	// MOSI pin (Master out, Slave in)
#define SPI_MISO PB3	// MISO pin (Master in, Slave out)
#define SPI_SCK PB1	// SCK pin (SPI clock)
#define SPI_SS PB0	// SS pin (Slave Select (not used))
// wait for an SPI read/write operation to complete
#define SPI_WAIT()              while ((SPSR & _BV(SPIF)) == 0);

// bit patterns for reading calib words and sensor data, and for sending reset
#define READ_W1 0b0001110101010000
#define READ_W2 0b0001110101100000
#define READ_W3 0b0001110110010000
#define READ_W4 0b0001110110100000

#define READ_D1 0b0000111101000000	// pressure read command
#define READ_D2 0b0000111100100000	// temperature read command

#define RESET   0b1010101010101010

The only thing worthy of comment is the read commands, which I had to pad out. The commands are only 10 or 12 bits, but we can left-pad them with zeros since the MS5541C will ignore anything it gets before the three-bit start sequence (111). When reading the four calibration words I also had to add an extra 0 after the three-bit stop sequence (000), because the sensor waits for one extra clock cycle before it starts sending back the calibration data. Same story with the commands to initiate pressure and temperature readings, except they wait for two cycles before starting the conversion so I padded them with two extra 0s after the stop sequence.

Function to send commands:

void send_bytes(uint16_t data)
{
	SPCR &= ~_BV(CPOL);
	SPDR = data >> 8;
	SPI_WAIT();
	SPDR = data & 0xFF;
	SPI_WAIT();
}

The commands are all 16 bits, just split them up and send them one byte at a time. SPI’s default is big-endian bit and byte ordering.  The first line of the function clears the SPI CPOL bit, which sets the polarity so that data are read (by the sensor) on the rising clock edge.

Function to read data back:

uint16_t get_bytes()
{
	uint16_t data;
	SPCR |= _BV(CPOL);
	SPDR = 0;
	SPI_WAIT();
	data = SPDR;
	data <<= 8;
	SPDR = 0;
	SPI_WAIT();
	data |= SPDR;
	return data;
}

Every piece of data is a 16-bit integer, so the program never has to read anything other than two bytes. Writing a 0 value to SPDR will initiate a transfer where the SPI module will send 0 on MOSI and read whatever the sensor sends back on MISO. Once SPI_WAIT() finishes, the incoming data will have replaced the outgoing data in SPDR and can be read back out. The second line of the function sets the CPOL bit so that data are read (by the microcontroller) on the falling clock edge.

Function to get calibration coefficients:

typedef struct {
	uint16_t SENST1;
	uint16_t OFFT1;
	uint16_t TCS;
	uint16_t TCO;
	uint16_t Tref;
	uint16_t TEMPSENS;
} coeff_t;

void get_coeffs(coeff_t* coefficients)
{
	uint16_t w1, w2, w3, w4;

	send_bytes(READ_W1);
	w1 = get_bytes();
	send_bytes(READ_W2);
	w2 = get_bytes();
	send_bytes(READ_W3);
	w3 = get_bytes();
	send_bytes(READ_W4);
	w4 = get_bytes();

	coefficients->SENST1 = w1 >> 3;
	coefficients->OFFT1 = (w1 & 0b111) << 10;
 	coefficients->OFFT1 |= w2 >> 6;
	coefficients->TCS = w3 >> 6;
	coefficients->TCO = w4 >> 7;
	coefficients->Tref = (w2 & 0b111111) << 6;
	coefficients->Tref |= w3 & 0b111111;
	coefficients->TEMPSENS = w4 & 0b1111111;
}

This function just reads the four 16-bit factory calibration words, and then unpacks them into the coefficients in the manner defined in the datasheet. The datasheet often refers to the coefficients as C1 through C6, they're in that order in the structure.

Reading the temperature:

int16_t get_temp_diff(coeff_t* coeffs)
{
	uint16_t T;
	uint16_t UT1;
	int16_t dT;
	int32_t dT_sq;
	send_bytes(READ_D2);
	_delay_ms(33);
	T = get_bytes();
	// find reference temperature
	UT1 = 8 * coeffs->Tref + 10000;	// maximum value is 42760
	dT = T - UT1;		// find difference between temperature reading and reference
	// calculate second-order temperature differential
	dT_sq = dT;
	dT_sq *= dT;	// dT squared
	dT_sq /= 128;
	dT_sq /= 128;	// looking for (dT/128) * (dT/128)
	if (dT >= 0) dT_sq /= 8;
	else dT_sq /= 2;
	// correct dT using second-order differential
	return dT - dT_sq;
	return 0;
}

int16_t get_temperature(int16_t dT, coeff_t* coeffs)
{
	int32_t acc = dT;
	acc *= (coeffs->TEMPSENS + 100);
	acc /= 2048;
	acc += 200;
	return (uint16_t)acc;
}

Temperature is obtained in two steps. First we get the temperature differential, which is the difference between the actual temperature and the reference temperature, Tref. Second we use that along with the TEMPSENS constant to calculate the actual temperature in units of 0.1°C (that is, a result of 200 corresponds to a temperature of 20.0°C).

I'm doing the second-order temperature differential correction as the datasheet suggests. At room temperature the second order differential is pretty close to 0.

Only the temperature differential is used to calculate the pressure. The actual temperature value isn't needed except for display and otherwise doesn't need to be calculated.

Calculating the pressure, in millibars:

uint16_t get_pressure(int16_t dT, coeff_t* coeffs)
{
	int16_t off;	// offset at temperature
	int32_t sens;	// sensitivity at temperature
	uint16_t P;		// pressure value
	int32_t pressure;	// actual pressure in mbar

	off = coeffs->TCO - 250;
	off *= dT;		// this shouldn't overflow, but watch out.
	off /= 4096;
	off += coeffs->OFFT1 + 10000;

	sens = coeffs->TCS + 200;
	sens *= dT;
	sens /= 8192;
	sens += coeffs->SENST1 / 2 + 3000;
	send_bytes(READ_D1);
	_delay_ms(33);
	P =  get_bytes();
	pressure = P;
	pressure -= off;
	pressure *= sens;
	pressure /= 2048;
	pressure += 1000;
	return (uint16_t)pressure;
}

This function just goes through the flow diagram in the datasheet. First it calculates the ADC offset and sensitivity, based on the temperature differential. Then it measures the actual pressure, and does math to it to convert the ADC units into millibars.

The datasheet specifies that each ADC conversion takes 33 ms to complete (I measured it to be around 31.3 ms). It actually outputs a trigger on the MISO pin whose falling edge indicates that the conversion is done. Unfortunately the SPI pins can't seem to be read without disabling the SPI module. One solution would be to tie the MISO line to an separate pin, and poll that while the conversion runs. The separate pin could also be an external interrupt that waits for a falling edge.  That's probably the right way to do it, but I just stuck in a busy wait.

The last software issue that needs to be considered is clock frequencies. The MS5541C has two clock inputs: MCLK, the master clock, and SCLK, the serial clock. The latter is generated by the SPI module, and can be at most 500 kHz. The former is intended to hook up to a 32,768 Hz clock source. It's unbuffered, so the clock voltage swing has to be the full TTL-compatible range. You could hook up a buffered watch crystal, I just generated a close-enough clock from the microcontroller as a PWM signal.

I've omitted the configuration code for the SPI, UART printing, and PWM signals. You can download the complete program here. The datasheet recommends averaging 8 samples to get an accurate result; I did not do so. The code assumes the following pin mapping to the digital pins on a Seeeduino Mega (AVR pin identifiers are noted in brackets):

MS5541C -> Seeeduino (AVR)
SCK -> D52 (PB1)
DOUT -> D50 (PB3, MISO)
DIN -> D51 (PB2, MOSI)
MCK -> D11 (PB5)
Vcc -> 3.3 V
GND -> GND

N.b. that the MS5541C is a 3.3 V device. The Seeeduino uses 5 V I/O, so the signal lines that go from the Seeeduino to the MS5541C (MOSI, SCLK, and MCLK) need to have voltage dividers or level shifters to step the voltage from 5 V down to 3.3 V. I used voltage dividers with resistor values of R1 = 22 kΩ and R2 = 43 kΩ.

]]>
Interfacing AVR/Arduino with the MS5541C pressure sensor https://nrqm.ca/2012/12/interfacing-avrarduino-with-the-ms5541c-pressure-sensor/ Mon, 31 Dec 2012 03:51:28 +0000 https://nrqm.ca/?p=833 The MS5541C is kind of an oddball sensor, BUUUUUUUT it’s small, it can be used underwater (with appropriate waterproofing), it’s cheapish (~$30), and Digikey sells it. It’s a pain to get running though, because of its hardware interface (50 mil pitch, surface mount (and not the good kind of surface mount either)) and its data interface (which doesn’t implement any particular standard protocol).

I tried carving out an interface board using some copper-clad PCB and a rotary tool, but I didn’t do a good job and it was really hard to get the 50 mil pads to line up with the messily-carved copper traces.  I used a heat gun to solder the sensor onto the PCB, and it almost worked—but two of the pins were shorted.  And of course a copper pad got torn off of the sensor when I tried to remove it from the PCB.  I bought another one and connected it to a 100 mil header via some ribbon cable.  That’s the wrong thing to do.  The datasheet specifies that the sensor should be securely fastened to a circuit board to prevent it from flexing, although it hints that might be just to prevent stress on the solder pads (which are, as previously noted, not incredibly strong) and not necessary to improve sensor performance.  The spec also says that a 47 μF tantalum decoupling capacitor should be placed as closely as possible to the sensor.  That is a noise reduction requirement, but whatever, there’s one on the Arduino that I have the sensor hooked up to and that’s good enough for now.  In any case, eucatastrophically, it works.

The data interface is a little easier to work out.  Like I said before, it doesn’t use a standard protocol, presumably to keep the internal circuitry as uncomplicated (and small and low-power) as possible.  The thankfully decent datasheet defines the protocol using electrical timing diagrams, and fortunately it’s simple enough once you work through it:

Example timing diagram for MS5541C.

Example timing diagram for reading W1 and W3 calibration words from the MS5541C internal ROM, copied from the datasheet.

There are six 16-bit data words that can be read over the MS5541C’s data interface (there are no writable words).  Four calibration words hold six constant values awkwardly packed together.  The other two words are to obtain the temperature and pressure measurements.  The diagram above shows the waveform diagram for reading two of the data calibration words, W1 and W3.  The waveform for the W2 and W4 words is identical except the rising edge that precedes the data signal on DOUT happens 1 clock cycle sooner.  The waveform for triggering the temperature and pressure measurements is also similar, and has a 33 ms conversion delay whose completion is signaled as a falling edge on DOUT.  You can look at the datasheet for more details on the protocol’s specifics.

You might look at that diagram and notice it’s a lot like an 8-bit SPI protocol, with a few subtle differences.  Well observed, hypothetical reader!  I think the protocol should be implementable using SPI, with these caveats:

  • The command pattern on DIN is 12 bits (10 bits for the temperature/pressure read commands, and 16 for the reset command).  This isn’t a problem, the command word can be padded out to 16 bits and sent as two bytes.
  • The sensor doesn’t send anything back on commands, and sends back data when receiving 0 bits.  No problem, just send 0 bytes to read the slave output and ignore the output when writing commands.
  • There’s no select pin, so you can’t put the sensor on an SPI bus unless you turn the sensor on and off at its power source.  This is fine as long as there’s nothing else on the SPI bus.
  • The DIN and DOUT pins are read 180° out of phase.  This is potentially a problem.

To elaborate on the fourth point, the sensor reads command bits from DIN (viz MOSI) on rising clock edges and returns data bits to DOUT (viz MISO) on falling clock edges.  In the AVR’s version of SPI data in either direction are always valid on the same clock edge: the rising edge by default, or, if the SPI module’s clock polarity bit is reversed, on the falling edge.  Hey, that suggests a solution to the 4th item:

reverse_polarity

You ought to be able to toggle the SPI module’s polarity bit between transmitting and receiving, so that the master transmits data on the rising edges and receives data on the falling edges.

I’ve implemented the code by bit banging because I didn’t notice the SPI similarity until I was done doing it manually.  It’s a mess.  When I’ve got the SPI version working I’ll put up some code.

]]>
Waterproofing 3D Prints (and also making them look super-cool) with Epoxy Clay https://nrqm.ca/2012/11/waterproofing-3d-prints-epoxy-cla/ Thu, 15 Nov 2012 07:29:51 +0000 https://nrqm.ca/?p=807 It’s pretty hard to get a watertight object out of our Makerbot Thing-O-Matic.  The walls of printed objects are pretty solid, but unexpectedly porous; even a thick block printed with 100% infill will allow water to penetrate it due to errors around the edges and imperfectly fused strands of plastic.  If you want to make a hollow object waterproof you’re going to have to do some post-processing.

It gets worse when the object is a curved surface, as is my AUV hull.  I’ve read that objects can be made watertight by adding outer shells.  That may be true for some objects, but on objects that curve along the z-axis the number of shells exposed to the surface grows as the tangent plane gets closer to parallel to the printer’s build platform—and big holes start to form.

My hull doesn’t actually have to be watertight, it’s a wet hull.  But it has to be airtight in order to hold the bubble of gas that controls the robot’s buoyancy.  Here’s what the airtight hull looks like:

Picture of Finished AUV Hull

Finished (‽) AUV Hull.

So that’s kind of neat.  I did the job using the following procedure:

  1. Clean the surface of each semidemihemisphere with isopropanol or something else that dries clear.
  2. Assemble each hemisphere with big wads of epoxy clay filling in the gaps between the four semidemihemispheres.  Then slather the assembled hemisphere in more epoxy clay so that it’s fully covered.  Then leave it until the clay cures.
  3. Sand down the epoxy clay until the plastic shows through (I used a 120-220-400-800 grit progression of sandpaper).
  4. Coat with lacquer to make it shiny.  I used shellac at first, then switched to polyurethane as it was easier to use (shellac has a very short work time and also discolours in water) and food-safety wasn’t a concern.

I actually did step 2 in reverse because I’m a terrible engineer and didn’t think to seal the gaps between the semidemihemispheres with clay until after I’d done the outer surfaces.

Epoxy clay turned out to be an effective material for smoothing and sealing 3D prints.  I bought 2 ounces of the reddish-brown (“flesh” coloured) stuff on eBay and later supplemented it with a 1 lb. white batch of the unsettlingly spelled Apoxie Sculpt from Sculpture Supply Canada (n.b. what I discovered regarding the difference between Apoxie Clay and Apoxie Sculpt).  The clay doesn’t adhere well to ABS as you’re applying it, I had to keep my fingers lubricated with water so that I could press the clay into the object’s filament ridges without the clay sticking to me.  (The water also made it easier to smooth the clay out so that I could squish it into a thin layer that was quick to sand down.)  Once the clay cures it’s really fricking hard to get it off of whatever it’s on, but it sands and drills cleanly.

The clay can also be used for filling holes and errant curves (e.g. due to the bottom of a print curling up as it cools) and for making good-looking, smooth, heat-resistant surfaces (I made a totally sweet coaster).  It also takes acrylic paint a little better than ABS plastic does, which isn’t saying much.

Another miraculous substance that I’ve discovered is Plumbing Goop.  It’s clear, creates a thin layer, is very easy to apply, and sticks really well to ABS.  It doesn’t peel off like silicone rubber.  It also provides a rubber-like grip, something that bare ABS is sorely lacking.  The downsides: because it’s applied in a thin, clear layer, it’s harder to get a thorough seal with Plumbing Goop than with epoxy clay; it doesn’t make spherical prints look like Jupiter; it doesn’t smooth out the filament ridges; and it’s flexible (comparable to silicone rubber), which might not actually be a downside depending on what you’re doing.

]]>
Underwater Solenoid Valve Remake https://nrqm.ca/2012/04/underwater-solenoid-valve-remake/ Sun, 22 Apr 2012 19:08:14 +0000 https://nrqm.ca/?p=767 I tried a solenoid I scavenged from underwater valves on my 3D printed valve system and it didn’t work (duh).  It was just too weak.  The original valve spreads the force from the high-pressure side across a larger area, so I guess the spring return can be comparatively weak.  My design didn’t do that.  I also didn’t cut my compression spring down very much, but I qualitatively determined that the solenoid wasn’t generating a useful amount of force by holding it on the magnetic core while turning the power on and off a bunch of times.  I am a terrible engineer.

So I went back to square 2 and decided to remake the original brass valve body in lighter ABS plastic using our Makerbot 3D printer.  The beta version looked like this:

Picture of a remade underwater solenoid valve with 3D-printed structure.

Remade underwater solenoid valve with 3D-printed structure.

I re-used the gasket, screws, core, and shaft from the original valve (where the solenoid sits), and replaced the big brass parts with light ABS plastic that is customized to fit onto my hull.  The steel shaft press-fits onto the shaft holder at the top of the photo.  The shaft holder screws into the connector piece, which implements the same idea as the brass valve piece, but instead of the input being a pipe fitting the input is open to the inside of the robot hull.  Note that in the photo I’m holding the valve upside-down, the solenoid shaft will hang down from the top of the robot hull, and the other end of the valve will bolt onto the hull’s top using the existing screw holes, pressing the base of the conical shaft against the hull’s top hole (apparently I’m a terrible photographer too).  When the valve opens, the air inside the hull will flow through the conical shaft out of the hull’s top hole and will be replaced by water flowing in through the bottom hole.

The new valve did in fact work.  The solenoid successfully pulled back the gasket to open the valve when activated, and it almost sealed when the power was disconnected.  The seal wasn’t perfect because it printed over a bump in the 3D printer’s build platform.  The plastic was 277 grams less massive than the original brass, and with a tweak or two the new valve will bolt onto the hull efficiently.

The valve had a few problems.  The steel shaft’s wide screw part was too wide for the hole it was supposed to screw into, so I had to file the hole out until I could press-fit the shaft in.  The support structures on the interface piece are too spindly, as you can see in the photo.  Also the square plate on the interface piece was a little thin, and it sat a little too short.  The corners  of the square hit other structures inside the robot hull, and it needed to be about 1 mm farther away from the nut holders.  In the new version I have tried to rectify these issues:

Model of a new version of the valve connector structure.

Updated valve connector structure.

The square plate is now half again as thick, and the nut holders (the bits sticking out near the top of the conical shaft) are 1 mm farther away from the plate.  The supports are a lot thicker, too: they’re 4 mm wide instead of 2 mm, and the six supports that don’t connect to the nut holders flare outward stylishly.

There’s one other issue that I foresee.  The heavy copper solenoid and the steel shaft/magnetic core sit pretty high in the hull, and raise the robot’s centre of mass.  This is a potential problem because if the centre of mass is too high the robot will roll too much in the water.  I can add extra ballast to lower the centre of mass, which may or may not be fine, depending on what kind of buoyancy the rest of the hull has.  I might actually have to do some engineering to figure that out.  Or, I can try it and see what happens.

]]>
Cravenly resorting to commercial solutions in underwater solenoid valves https://nrqm.ca/2011/12/cravenly-resorting-to-commercial-solutions-in-underwater-solenoid-valves/ Sat, 24 Dec 2011 06:16:13 +0000 https://nrqm.ca/?p=683 I’m having trouble with the upper valve that will allow air to be released from the hull (thus decreasing buoyancy and giving some downward thrust).  I mean, I’m having trouble with everything, but that’s why I’m doing this, right?  Anyway, I decided to order a couple underwater solenoid valves in the hope that I could stick one in the robot and have it work (hahahahaha).  I found several suppliers in China listed on this site alibaba.com, and settled on Nuoling Pneumatic.  Most of the other options either weren’t waterproof, were too big, didn’t support a 12 V power supply, or had a large minimum order size. The two I bought were $12.35 each, which is less than I was expecting (although the shipping was $55 for two units).

Underwater solenoid valve from Nuoling Pneumatic

Underwater solenoid valve from Nuoling Pneumatic

The valves were a lot bigger and heavier than I expected.  You can see it’s basically a big chunk of brass connected to the waterproof electrical components.  Fortunately it’s easy to take apart:

Inner workings of a solenoid valve.

Inner workings of this solenoid valve.

The valve assembly consists of three parts: the brass base; a rubber gasket connected to the spring-mounted iron solenoid core; and a metal sheath that encloses the core, bonded to the upper brass component.  (The solenoid is mounted on the metal sheath.)

Inside the solenoid valve's brass base.

Inside the solenoid valve's brass base.

The above photo shows the structure inside the brass base.  Notice the arrow indicating the expected direction of flow through the valve.  The rubber gasket seals the inner aperture, and the pressure of the incoming fluid is dispersed around the perimeter of the large outer chamber so that it doesn’t push the gasket up.  When the solenoid is activated it pulls the iron core up, which pulls the gasket away from the inner aperture.  Fluid flows under the lifted gasket into the aperture until the solenoid is de-energized, at which time the iron core is released and the spring return pushes the gasket against the aperture’s lip to seal it back up.

Solenoid valve specification.

Solenoid valve specification.

This label shows the valve’s specification, including the desired 12 V power supply.  In fact, I tested with a fully charged 7.2 V Li-ion battery and it still actuated in air.  The operating pressure label is a little disconcerting, as the datasheet the supplier sent me specified a working pressure of up to 500 kPa.  A 0.10 kgf/cm^2 pressure corresponds to less than 10 kPa.

The valve's waterproof solenoid.

The valve's waterproof solenoid.

The solenoid is made of a copper winding connected to some nice, solid leads.  The winding is coated in an encapsulant, which is a pretty thin layer of some kind of urethane-like material, and wrapped in a fabric mesh to hold everything together tightly.  I haven’t tried it underwater yet, but this part (housed in the black casing in the photo at the top of this post) is exposed to the environment so I assume it’s actually waterproof.

This may turn out to be the most useful part of the valve.  I don’t think I can justify putting all that brass and steel in my underwater robot, it’s just too heavy.  By a happy coincidence, the valve I made previously fits perfectly inside this structure, so hopefully I can just mount this solenoid on my existing valve (or maybe an elongated version of the current valve.  I tried, and my spring return is too strong–the compression spring on the solenoid’s iron core is surprisingly febrile–but this gives me hope that I can cut it down further and reduce the amount of force needed to pull the valve open.

One problem I foresee is that in my configuration, the transvalve pressure will be pushing the valve closed, so the deeper the robot, presumably the more force is needed to open the valve.  It’s not a big deal, it will just limit the robot’s depth, which is better than making the robot unrecoverable.  I’ll be happy if the stupid valve opens at all.

]]>
Un-improving range on the infrared channel https://nrqm.ca/2011/10/un-improving-range-on-the-infrared-channel/ Tue, 04 Oct 2011 03:51:46 +0000 https://nrqm.ca/?p=668 It turned out doing software UART was a terrible idea.  The processor is way too slow to support a reasonable baud rate.  I did figure out how to use a comparator though: the key phrase I was missing was “rail-to-rail.”  That means that inputs can be in the full voltage range from ground to Vcc.  Another handy phrase is “push-pull,” which means that the comparator can output 0 and 1; in contrast, an “open collector” comparator can only output 0, and needs an external resistor to pull the output to 1.

I bought a rail-to-rail push-pull comparator, the MCP6541, and tried it with the receiver circuit, and sure enough it increased the maximum range significantly.  Unfortunately it also increased the minimum range significantly.

Here’s the circuit diagram for the modified receiver circuit:

Infrared receiver with comparator for amplification.

Infrared receiver with comparator for amplification.

The 1 kΩ and 10 kΩ resistors are in a voltage divider configuration to generate a 3.0 V reference against which the input is compared.  If the input is higher than 3.0 V, the comparator outputs 3.3 V, and otherwise the comparator outputs 0 V.

I guess there are a bunch of transistors inside the comparator, and putting them in a chain with the pair of external transistors messes things up.  I don’t know why, but it might be a gain-bandwidth thing (too much gain, lowers the maximum frequency the circuit can operate at).  This is what the output looks like at about 6.5 cm:

'U' character sent over infrared with infrared amplifier.

'U' character sent at 19200 bps over infrared with comparator amplifier.

The jagged bits aren’t there without the comparator.  I used the U character to test because its binary pattern is 01010101.  As you can see, the pattern is there but it’s kind of messed up and it’s dangerously close to 3.0 V.  (Now that I look at this again I see maybe reducing the 3.0 V threshold would improve the minimum range.)

I figured I could put an OPA2134 op-amp voltage follower in between the external transistors and the comparator.  This would de-couple the two sets of transistors, so the weird transistor chaining effect would disappear.  This worked perfectly, once, for no apparent reason at all.  Eventually, after spending a day trying to reproduce my success, I read the op-amp’s datasheet more closely and discovered that it’s not rail-to-rail and should never have worked (it can’t output the full 3.3 V signal, so the comparator’s input was never reaching 3.0 V).

I switched to a JFET op-amp that had rail-to-rail output, and it was able to transmit the ‘U’ character at a good set of ranges, both small and large.  Unfortunately this is the signal it was outputting, at 7.5 cm and at 2 cm:

'U' sent at 19200 bps over infrared with JFET voltage follower at 7.5 cm.

'U' sent at 19200 bps over infrared with JFET voltage follower at 7.5 cm.

'U' sent over infraret with JFET voltage follower at 2 cm.

'U' sent at 19200 bps over infrared with JFET voltage follower at 2 cm.

The observant among you, my imaginary audience, will notice two strange things from this screenshot:

  1. The signal is peaking at almost 4 V.
  2. It’s sending 9 bits at 7.5 cm and 19 bits at 2 cm.

Hoo boy, it didn’t work at all, and it was pure luck that the ‘U’ transmitted correctly at short range (followed, presumably, by a framing error that my system silently ignored).  No other character worked.

I found out that you can use an op-amp as a comparator, so I tried that with my OPA2134:

'U' sent at 19200 bps over infrared with op-amp comparator.

'U' sent at 19200 bps over infrared with op-amp comparator.

Okay!  You can see what it means that the amplifier is not rail-to-rail, it’s only going up to 2.6 V (and that only briefly), but if I remember correctly it received.  Unfortunately the high bits got narrower for some reason as the range decreased, so it didn’t actually do anything to solve the range problem.

I tried using the JFET amp as a comparator, but it didn’t output anything at all so I gave up and ignored the project for a few weeks.  My current solution is to pretend there isn’t a problem, and if I run into the  minimum range issue then I can just bend the receiver askew so that the signal is damped enough to receive.  In the meantime, the transmitter now has a wider field of view, which ought to make it easier to place several receivers in range of the control unit.

]]>
Improving range on the infrared channel https://nrqm.ca/2011/09/improving-range-on-the-infrared-channel/ Sat, 03 Sep 2011 19:15:55 +0000 https://nrqm.ca/?p=663 The range on the infrared channel, which I discussed in the last entry, is probably enough; but I’d like to increase it a bit.  With more range I can space modules farther apart if needed, and hopefully be able to have a wider angle between the transmitter and receiver.

Fortunately the signal output by the Darlington transistor pair on the receiver is a pretty clean digital signal.  At full power it ranges from (a little above) 0 V to (a little below) 3.3 V.  As the transmitter gets farther away the digital signal remains but the low voltage increases beyond the UART receiver’s ability to read a 0.  For example, at a large distance the UART signal might range from 2.5 V (logical 0) to 3.3 V (logical 1).

There are several options I’ve considered:

The handy old Schmitt trigger is the most straightforward, but it’s touchy to design and it will add a bunch of parts (an op-amp and a bundle of resistors).  I tried using a comparator chip, which is like the Schmitt trigger but simpler, but I found that it had a big limitation.  It worked, but the inputs can’t exceed Vcc – 1.5 V (the “common mode input voltage range” on the datasheet).  It can’t read a digital signal ranging between 1.8 (or more) and 3.3 V, so it would provide some amplification but not a lot.  I’m targeting 90% of Vcc as my threshold, so it should read anything below 3.0 V as low.  I also considered using another PNP transistor to amplify the difference between Vcc and the input voltage, but: that much amplification is risky noisewise, an extra transistor reduces the bandwidth too much, and the PNP transistor will produce a logically inverted signal.

Another option is to amplify the signal using crazy op-amp magic, but aaaaaaah no.

So I tried thinking like I’m supposed to for once, and I’m going to try a software solution.  AVR processors include an analog comparator, which I can (hopefully) use to amplify the digital signal coming from the infrared optotransistor.  The downside to doing it this way is that it bypasses the UART module, which means that the application needs to receive data manually (I can still use UART to transmit the signal).  Receiving data will tie up the processor, but as long as there’s enough time to run the receiver code it should be okay, I don’t foresee much data traffic.  Here’s a potential flow chart for the receive procedure:

Software receiver flow chart.

Software receiver flow chart.

Some notes:

  • The wait process is a euphemism for “disable the timer, store the data, blah blah blah, then go back to the program until the next start bit.”  This process takes place during the stop bit, so if there’s another byte incoming then it should finish in time to receive the next start bit.
  • Kevin Rosenberg’s awesome tool AVRCalc calculates that the 8-bit timer running at 8 MHz can be used to generate a 57554 Hz interrupt rate using an OCR value of 0x8A.
  • I might need to mess around with the timing so that the AC reads the right bit, but probably not.  There should be plenty of interrupt overhead delay, and the sampling rate is a little slow and will drift toward the end of the bit.
  • I’m not sure how long the analog comparator takes to produce a result but I’m guessing it’s pretty fast because it doesn’t have to do much.  The AVR datasheet doesn’t have much information on it.  I also don’t know if the comparator has a large common mode input range.

Failing that, I can look for an external comparator with a large common mode input range, or just suck it up and use an op-amp.

]]>
Transmitting UART serial over infrared https://nrqm.ca/2011/08/transmitting-uart-serial-over-infrared/ Sat, 20 Aug 2011 04:50:34 +0000 https://nrqm.ca/?p=658 Here’s how I’d like to communicate between modules in the AUV:

UART-over-IR transmitter (left) and receiver (right).

This is how it works:

For the transmitter I’m using a TSAL6100 infrared emitter.  The LED is rated to operate at 100 mA, which the 15 Ω resistor generates (I actually calculated a 22 Ω resistance and bought 22 Ω resistors; two of those in series, in parallel with another one results in around 15 Ω).  I will actually use a 10 Ω resistor to get a bit more power out of the LED.  This is safe because the LED will only be turned on for brief periods.

The transmitter uses a PNP transistor.  When the Tx-o pin is low, current will flow from the emitter (the side with the arrow) into the base (the Tx-o pin) and the transistor will open, sending current to the LED.  When the Tx-o pin is high current will not flow from the emitter and the transistor will be closed.  This effectively inverts the UART signal, which is good because the Tx-o line spends its idle time high and only goes low when sending data.  The LED only turns on when the Tx-o pin is sending a 0.

The receiver circuit is based around a TEFT4300 phototransistor.  The current generated by the phototransistor is amplified by another NPN transistor (i.e. a Darlington pair configuration).  The resistor is a pull-up resistor, keeping the Rx-i line high while idle.  When the phototransistor is activated by the transmitter LED (a 0 bit is transmitted), the signal is amplified by the NPN transistor and the Rx-i line is pulled to slightly above ground.

I found that the pull-up resistor in the receiver circuit is a little sensitive.  With a 10 kΩ resistor the receiver is not responsive enough to generate a square wave matching the transmitted signal.  With a 10 Ω resistor the NPN transistor saturates and never reaches the low threshold.  I tried the 1 kΩ resistor and a 390 Ω resistor, and qualitatively decided that the 1 kΩ gave a little more range.

The transistor switching frequencies determine the maximum speed of the UART link.  The NPN and PNP transistors both have bandwidths exceeding 1 MHz under the conditions presented above.  The phototransistor is limited to 180 kHz, which is plenty for this application.  It is sufficient to program an Arduino (57600 bps) or Netduino (115200 bps) wirelessly.  More bandwidth could be obtained using photodiodes, which are very fast but a little more expensive than phototransistors.

I haven’t measured the range of this system yet, but eyeballing it it’s around 15 cm with the 10 Ω resistor on the transmitter.  I could improve this by amplifying the signal at the receiver (e.g. with a Schmitt trigger), but 15 cm is probably enough for my application, as long as it works underwater.

]]>