Archive for June, 2010

4046 VCO Final Breadboard Proto

Monday, June 28th, 2010

So this weekend marked the last screwing around (breadboarded, at least) with the VCO design for WTPA2. I knew that I could get the frequency range I needed out of a 4046 based VCO with a current sink in place of a frequency setting resistor but I was a little worried about temperature drift and very low frequency performance. Just for shits, I gave the circuit above a shot. It replaces the current sink with a standard two-transistor current mirror. The two devices above are crappily thermally coupled with a piece of heat shrink.

What I found with this is that temperature performance wasn’t too much better. It was still pretty easy to get this VCO to go crazy with the heat gun, although it was possible to get it to go crazy BI-DIRECTIONALLY based on the direction you were slathering on the sweat. Cute, but not useful.
One thing that WAS cool is that the current source compliance was great! The control voltage could get a lot higher than it could with the one-transistor sink before saturation, I assume because of the lack of emitter resistors in the circuit. Still, that was like a consolation prize.

So I caved and built this:

Here’s the schematic for it:

It’s what all the docs I saw suggested originally (a closed loop current sink where the op-amp compensated the temp drift of the transistor) and it totally works and does what it’s supposed to. The only annoying thing is that at VERY low currents the device is non-linear, but what are you gonna do. At a hundred Hz sampling rate all samples sound like farts anyway.

The CV has to be kept below about 2.2v to keep the transistor from saturating (the VCO goes nuts when this happens) but you can fix this with a divider on the input. The range with these components is about 0-20kHz with a CV from 0 to 2.1v or so.

Now I gotta figure out what to do with that other half of the 358. I sort of don’t want to pass it audio, because it’s a recipe for coupling noise into the circuit. We’ll see….

This week I’m working on the board layout for the first WTPA2 revision. I expect the next post here will be about that.
xo
TB

Infinite Impulse Response, Art, Flatulence

Friday, June 25th, 2010

So I got back from Chicago on Monday, where I went to take care of this blighted piece of public art. “Remoc” is this big old green beast who I made with a sculptor buddy back in like 2005, at the behest of my old boss, for the UChicago Childrens’ Hospital. Theoretically he makes sick kids laugh. I’ve seen this. I know it happens sometimes. Usually when you pull his finger, as above. However it is hard not to see him as basically a monster whose job it is to complicate my life.

In some earlier posts I talk about some of the capacitive sensors I designed for him, to allow him to sense childrens’ touches. Well, they developed problems (spurious reads) and I had to head back to the midwest to have a look.

I knew his sensor circuits were pretty resolute, but I basically no-brainered his sensor code because I was too confident in my design. The day before I left to head back to the windy windy I re-wrote a bunch of his sensor handling code.

Mostly I changed how he crunches numbers. Sensor data ends up getting put into two different filters; one with a long time constant and one with a short one. His long term averages are generated by an IIR which divides by 8192, so it takes something like 73,000 readings to settle from 0 to 4096 (12-bit sensors). Sensors were updated in the main game loop, so the loop timing was “fast but indeterminite”. I’d have scoped it, if I had a scope and the hardware in the same place. In real life it took him five minutes or so to settle from any particularly messed up event (like unplugging a sensor).

The short term averages do the same thing over 32. I tried using an FIR (where you have an array and subtract an old member and add in a new one) for this but it ended up being more of a pain in the ass as I kept missing some stupid bug I was making where I wrote off the end of an array so I just made it an IIR since there were people watching and expecting results.

The two were then compared via percentage difference. I also changed the way his serial monitor worked to make it easier to see all this data change in realtime (I’ve gotten really into sending ANSI clear-screen escape sequences to xterm. It’s hood, but it works).

What I learned from this was two of his ten sensors (the copper tape parts, installed in his bowels a million years ago, and also set on fire once or twice by the sculptor) have shifted positions — I could see this by looking at the readings and moving my hand around. So there was no fixing this (correctly) without cutting a lot of fiberglass. I asked the hospital folks whether they would be OK with cutting his arm off for a little while and surprisingly they said no. Which was just fine with me. I did what I could with the data coming out but it wasn’t much. You may have to womp on his cast really hard to trigger it now, but it won’t read spuriously.

While sensor-sensor interference may be a little bit of a problem, I could also could tell that there were bigger EMI problems, generated by switching the LEDs and PWM audio. Those sensors are relatively insensitive to LF noise, but not so much to HF, which I’d change in future sensor designs. For the nonce I changed when the sensors were polled in the game code and disregarded reads which happened during electrically noisy events.

You know, regular electronics stuff:-)
I’d love a chance to do him all over again, but until then, I’m _almost_ happy with how he is.

Here’s some of the code I used.
The following updates his averages/filters:

static void UpdateTouchsensorAverages()
// Work averaging magic on sensor readings.
// Capacitance is indicated by low readings.  When the readings increase it means a removed hand OR a temperature rise.
{
	unsigned int 
		temp,
		i;
	
	for(i=0;i<NUM_SENSORS;i++)
	{
		temp=adcResults[i]; 							

		// Update long term reading
		sensorLongTermAverages[i]-=(sensorLongTermAverages[i]/LONG_TERM_AVG_DIVISOR);		// Remove a chunk of the average.
		sensorLongTermAverages[i]+=temp;													// Add in our new sample into average.

		sensorShortTermAverages[i]-=(sensorShortTermAverages[i]/SHORT_TERM_AVG_ARRAY_SIZE);
		sensorShortTermAverages[i]+=temp;
	}
}

This next bit compares the two values and decides whether he is “touched”:

static unsigned int TouchsensorsToKeyStates()
// Take the touchsensor readings, look at thresholds, and make them into keypresses.
// Since there are no real keys in this application, this is straightforward.
// We will just pass this directly to keyStates.
{
	unsigned int
		i,
		tempMask;
	
	tempMask=0;									// Zero out "keys".

	for(i=0;i<NUM_SENSORS;i++)					// Make keys that correspond to all sensors.
	{
		if((sensorShortTermAverages[i]*SHORT_TERM_MULTIPLIER)+((sensorLongTermAverages[i]*sensorThresholdPercentage[i])/100)<=sensorLongTermAverages[i])		// Scale up the short term reading, add it to a determined percentage of the long term.  If the sum is less than the long term average, call it a touch.
		{
//			printf("TOUCH: %d\n",i);
			tempMask|=(1<<i);													// Mark this sensor as a pressed key.
		}
	}	

	return(tempMask);
}

and this last part spits out RS232 data when I tell it to so I can “see what he’s feeling” like a marriage counselor:

static void DisplayAdcValues(void)
// Monitors Adc Shizz.  Prints out variables and touch info.
{
	unsigned int
		i;
	unsigned char 
		inputChar;

	if(CheckTimer(TIMER_1))
	{
		ResetTimer(TIMER_1);

		SerialWriteByte(DEBUG_UART,'\e');	// ANSI clear screen.  Old skool!
		SerialWriteByte(DEBUG_UART,'[');
		SerialWriteByte(DEBUG_UART,'2');
		SerialWriteByte(DEBUG_UART,'J');

		printf("x to Exit\n");

		for(i=0;i<NUM_SENSORS;i++)
		{
			printf("S:#%d adc=%d L=%d S=%d DP= ",i,adcResults[i],sensorLongTermAverages[i],(sensorShortTermAverages[i]*SHORT_TERM_MULTIPLIER));	// Print the sensor number and its averages.

			if(sensorLongTermAverages[i]>(sensorShortTermAverages[i]*SHORT_TERM_MULTIPLIER))	// FIR is less than the IIR (this is how it should be when touched)
			{
				printf("-");
				printf("%d",((sensorLongTermAverages[i]-(sensorShortTermAverages[i]*SHORT_TERM_MULTIPLIER))*100)/sensorLongTermAverages[i]);	// Print percent difference the short term is from the long
			}
			else	// FIR is greater.
			{
				printf("+");
				printf("%d",(((sensorShortTermAverages[i]*SHORT_TERM_MULTIPLIER)-sensorLongTermAverages[i])*100)/sensorLongTermAverages[i]);	// Print percent difference the short term is from the long		
			}

			if(keyState&(1<<i))	// Touched?
			{
				printf(" ***\n");
			}
			else
			{
				printf("\n");			
			}
		}		

		printf("\n");
	}
	else if(SerialRxBytesWaiting(DEBUG_UART))		// Something in the buffer?
	{
		inputChar=SerialReadByte(DEBUG_UART);	// Get it.

		if(inputChar=='x')
		{
			printf("\nMonitor Done.  Hope you learned something.  Bye!\n");
			SetGameState(RemocTerminal);
			gameSubState=GSS_0;
		}
	}
}

This is all C code (duh) which is compiled with GCC for an M68k target.
In this case, as in so many when I am lost in the programming weeds, my buddy Todd Squires gave me tons of useful pointers.

It is also worth noting that a more positive analysis might paint Remoc as an excuse to spend a weekend in my old hometown drinking beer on the Metra tracks and eating the worlds finest tacos, which exist in Chicago, and which pretty much grow on trees.

xo
TMB

WTPA2 4046-based V-to-F Circuit, take 2

Saturday, June 12th, 2010

Boom! Current sinks all the way:

Because I am late to a BBQ I will not bother here to kick on the corporate dog and grumble about how not a single Rat Shack in downtown Brooklyn sells solderless breadboards. I will however sing the praises of H&H (buy that book. I’m not kidding) and the value of the current sink in the previously discussed VCO clock circuit. I soldered this mess up on some perfboard and in short order had a VCO that happily went from DC to >> 1MHz! The linearity is TERRIBLE, but it proves that the range is there. I’m pretty sure I can fix it adequately for my needs with just fiddling with the passive components in this circuit. Hopefully. Here’s the schematic, captured in time honored analog fashion:

Those component values are way stupid, but I think this is the topology. I may yet get away without the op-amp. Live and learn. And happy BBQing.
xo
TMB

WTPA2, Current Sinks, and the 74HC4046

Wednesday, June 9th, 2010

So once again somebody on the forum came through and found this guy’s page about designing a switched capacitor filter, where he talks about using a CURRENT SOURCE (sink, actually) instead of a resistor on one of the 4046’s frequency setting pins. This was a real forehead smacker. Thanks Kyle (erschlagener) for the heads up, and thanks to Tim for putting that out there in the first place!

Requisite googling found an EDN note about this, too:

Which claims a 1000:1 frequency range out of the 4046’s VCO!
It also confirms what I’d found on the breadboard before, namely that the 4046’s frequency output is not particularly linear outside of about 1v-4.75v, and that inside there you can expect to get about a decade of range. So I felt less dumb.

This note also has the bright idea of putting the sink in the feedback loop of an opamp, which almost certainly helps linearize the sink’s behavior at low voltages by getting rid of base current related weirdness.

Enter a quick trip to findchips for some pricing data. Turns out that the 4046 and a transistor are certainly cheaper than the LM331, although they take up more real estate. Even throwing in an cheap LM358 still costs less than the LM331, although the savings start to get less significant. Now, if there was some good use for that second op-amp in a ‘358, that’d be something…

This recalls some quote I heard and want to attribute to Jim Williams, though I can’t recall exactly where it’s from, about how in modern circuits like 80% of the thing is digital and takes 20% of the time to design, whereas the 20% that’s analog takes the 80%. Sometimes it does seem true, although it might just be (for me anyway) that the analog parts are a lot of fun :-)

Back to the breadboard!
xo
TMB

Dancing Stands Get All ED-209

Monday, June 7th, 2010

So, because it isn’t actually in a show yet I can’t talk about what this new dancing stand is for, but it may or may not be capable of beating up Robocop. Suffice it to say, the old gearmotor has been removed from this stand and replaced with a two-pound tank which comes as a separate synchronous motor and gearhead.

This also continues the fascinating if slightly worriesome Spring 2010 trend of my clients viewing me as a one stop for assembly language and abrasives, but things are slow so I’ll take it.

The new gearmotor was similar in size to the old one, but not so similar that it didn’t mean cutting out a big piece of the steel doghouse, making some aluminum mounts to hold the motor, drilling out the timing pulleys to fit the new motor shaft, and putting a detent in said shaft to seat the set screw. I also got my first set of metric taps, so that I could use M4 screws in this guy and the hardware I put in would match the hardware from the factory. This, O art world, is the attention to detail you get when you hire C Programmers to get their thread-cutting on.

Here she is all buttoned up.

Though I have a sneaking feeling Cory doesn’t really care about what the bottom of these things look like, I kinda do. Plus I figure the dust cover, you know, keeps dust out. Plus I had just gotten these really cool carbide burs and I was excited about cutting more holes in stuff.

Perhaps one day, one of these things will have a stepper motor or optical encoder or SOMETHING with silicon in it and everything will come full circle.