Dry Water

My first thought was that you can’t make this stuff up:

Dry Water - Pok RR Station
Dry Water – Pok RR Station

That’s taken through one of the windows over Track 3 at the Poughkeepsie railroad station, so it’s a bit blurrier than usual.

It turns out a “Dry Water” pipe delivers ordinary water, but normally contains pressurized air to prevent freezing. An intricate valve in a heated room balances air pressure in the pipe against the supply water pressure; when the air pressure drops, water flows through the valve to the outlet.

Normally, you’d use a Dry Water pipe in a fire suppression system, but it makes perfect sense for an outdoor hose bib (or whatever you call that quick disconnect fitting) on the top level of the Poughkeepsie Railroad Station.

There’s (almost certainly) an automatic drain valve that removes water from the dry pipe: otherwise, it’d remain full after use and pop the pipe during the next freeze.

Makergear M2: Platform Leveling with Cart Coins

It turns out that an array of Cart Coins and Cart Releasers make a fine thickness test pattern and become useful tchotchkes when you’re done:

Cart Coins - printing
Cart Coins – printing

They’re a bit easier to see in the digital realm:

Cart Coins - platform layout - layer 1
Cart Coins – platform layout – layer 1

The trick is that they’re both eight layers thick at 0.20 mm/layer. With the platform aligned exactly right, all the objects should measure exactly 1.60 mm thick.

The blue numbers give the thickness measured across the stem, just above the hole, on each object:

Platform Leveling - Initial
Platform Leveling – Initial

The green numbers are the skirt thickness: 22 = 0.22 mm.

The platform has a tilt of 0.20 mm from +Y to -Y and is just about perfect from -X to +X.

The M3x0.5 adjusting screws under the (improved) platform, seen from the front (-Y) end of the platform:

M2 - Improved HBP - bottom view
M2 – Improved HBP – bottom view

The silicone plugs inside the springs are slightly compressed, so the springs are only decorative. The platform is rigidly mounted on the plugs, with only very slight compliance, and I haven’t leveled the platform in a few months.

Tightening the “north” adjusting screw by 1/6 turn lowered the +Y end of the plate by about 0.05 mm and tilted the +X side slightly higher:

Platform Leveling - Adjustment 1
Platform Leveling – Adjustment 1

The skirt thicknesses are now in blue, too.

Tightening the “north” screw an additional 1/6 turn and tightening the “east” screw 1/6 turn produced an almost perfect result:

Platform Leveling - Adjustment 2
Platform Leveling – Adjustment 2

The thicknesses don’t vary quite randomly, but I think further adjustments won’t make much difference: the total range is only 0.12 mm = 1.53 to 1.65 mm. That’s pretty close to the limit of my measurement ability on the plastic pieces.

Notice that the skirt thread, which should be exactly 0.2 mm thick all around, really isn’t. I’m going to see whether a two-layer-thick skirt measures a more consistent 0.40 mm.

Dell Dimension 2300: Capacitor Plague

While scrubbing a hard drive and decommissioning an old Dell Dimension 2300, I spotted a failed capacitor:

Dell 2300 failed capacitors - 1
Dell 2300 failed capacitors – 1

And another:

Dell 2300 failed capacitors - 2
Dell 2300 failed capacitors – 2

The board sported many of those little caps, well over half showing signs of distress.

A progression of victims, from I’m-not-dead-yet to phew:

Dell 2300 failed capacitors - grouped
Dell 2300 failed capacitors – grouped

According to its Service Tag, this Dimension 2300 came off the line in late November 2002. All of the other caps on the board seemed OK, so apparently the plague affected just this lot of Hermei 470 µF 6.3 V capacitors.

Or, hey, they’re not supposed to last a dozen years and this is perfectly normal …

Twiddling Linux Swap Performance

Depending on a solid model’s complexity, OpenSCAD will sometimes chew through system memory, consume the entire swap file, and then fall over dead. In an attempt to work around that situation, I recently jammed a 32 GB USB drive into the back of the box, turned it into a swap device, and then told the kernel to back off its enthusiasm for swapping.

Format the USB drive as a swap device:

sudo mkswap /dev/sd??   #--- unmount it before you do this!
Setting up swapspace version 1, size = 31265292 KiB
no label, UUID=0f559a8c-67b7-4fa3-a709-17aeec3104c4

Add it to /etc/fstab and set swap priorities:

# swap was on /dev/sdb3 during installation
UUID=e8532714-ad80-4aae-bee7-a9b37af63c8c none  swap sw,pri=1	0 0
UUID=0f559a8c-67b7-4fa3-a709-17aeec3104c4 none	swap sw,pri=5	0 0

Turn it on:

sudo swapon -a

Following those directions, dial back the kernel’s swappiness and limit the file cache growth:

sudo sysctl -w vm.swappiness=1
sudo sysctl -w vm.vfs_cache_pressure=50

Those commands now live in /etc/sysctl.d/99-swappiness.conf:

cat /etc/sysctl.d/99-swappiness.conf
# Improve responsiveness by reducing cache swapping

For whatever reason, WordPress turns underscores into blanks, so those obvious typos aren’t, really.

And then it should Just Work.

The box has 4 GB of RAM and, under normal circumstances, doesn’t swap at all, so I expect the USB drive should kick in only for extreme OpenSCAD models. The swappiness tuning should help during ordinary operation with large file operations.

I have no results to report, but if something blows up, I know what changed…

Hall Effect LED Current Control: Crisp Gate Drive Shaping

Because the current control loop closes through the Arduino loop(), the code’s path length limits the bandwidth. Worse, the PWM filter imposes a delay while the DC value catches up with the new duty cycle. Here’s what that looks like:

LoopStatus ILED 50 mA div - 200 50 150 25 mA
LoopStatus ILED 50 mA div – 200 50 150 25 mA

The setpoint current for this pulse is 200 mA, ramping upward from 50 mA. It should have started from 25 mA, but the loop really wasn’t under control here.

The top trace goes low during the drain current measurement, which occurs just before the code nudges the gate drive by 1 PWM count to reduce the error between the setpoint and the measurement. A delay(1) after each PWM change, plus the inherent delay due to all the program statements, produces an update every 1.7 ms, more or less.

Even at that low rate, the current overshoots by 50 mA before the loop can tamp it down again. The current varies by 200 mA for 7 PWM counts, call it 30 mA per count at the high end, so overshooting by 50 mA comes with the territory. There’s just not a lot of resolution available.

The program reads each pulse duration and amplitude from an array-of-structs, so it’s a simple matter of software to save the gate drive voltage at the end of each pulse and restore it when that pulse comes around on the guitar again:

	if (millis() >= (EventStart + (unsigned long)Events[EventIndex].duration)) {
		Events[EventIndex].drive_a = VGateDriveA;						// save drive voltages
		Events[EventIndex].drive_b = VGateDriveB;

        if (++EventIndex > MAX_EVENT_INDEX)								// step to next event
		    EventIndex = 0;

		VGateDriveA = Events[EventIndex].drive_a;						// restore previous drives
		VGateDriveB = Events[EventIndex].drive_b;



		digitalWrite(PIN_ENABLE_A,Events[EventIndex].en_a);				// enable gates for new state

        NeedHallNull = !(Events[EventIndex].en_a || Events[EventIndex].en_b);	// null sensor if all off

		EventStart = millis();                                          // record start time

… which produces this happy result, with a different time scale to show all four pulses in the array:

I Sense Amp  ILED 50 mA div - 200 100 150 50 mA
I Sense Amp ILED 50 mA div – 200 100 150 50 mA

The top trace shows the current amp output that goes into the Arduino analog input and the bottom trace shows the MOSFET drain current. Notice those nice, crisp edges with a nearly complete lack of current adjustment.

The small bumps in the amp output just after the LED turns off happen while the the code nulls the Hall effect sensor offset. Whenever the LEDs turn off, the code nulls the sensor, which is probably excessive; it really doesn’t have much else to do, so why not?

This trickery doesn’t improve the loop bandwidth at all, because the code must still drag the current to meet each setpoint, but now that happens only when the pulse first appears. After a few blinks, the current stabilizes at the setpoint and the loop need handle only slight variations due to temperature or battery voltage changes.

Speaking of voltages:

VDS ILED 50 mA div - 200 100 150 50 mA
VDS ILED 50 mA div – 200 100 150 50 mA

The top trace now shows the MOSFET drain voltage and the bottom still has the LED current. There’s only 650 mV of difference at the drain for currents of 50 mA and 200 mA through the LEDs, with about 1 V of headroom remaining at 200 mA.

The power supply delivers 7.4 V to the anode end of the LEDs, so they drop 6.3 V @ 200 mA and 5.7 V @ 50 mA. Some informal knob twiddling suggests that the MOSFET loses control authority at about 6.5 V, so, given that there’s not much energy in the battery below 7.0 V anyway, the program could limit the  maximum current to 50 mA when the battery hits 7 V, regain 650 mV of headroom, and run at reduced brightness (and perhaps a different blink pattern) until the battery drops to 6.5 V, at which point the lights go out.

There’s more improvement to be had in the code, but those pulses look much better.

(If you’re keeping track, as I generally don’t, this is Post Number 2048: love those round numbers!)

Hall Effect LED Current Control: 64 kHz PWM

The original 32 kHz PWM produced plenty of ripple in the LED current:

VG 1193 mV - ID 50 mA-div - 1 ms PWM filter
VG 1193 mV – ID 50 mA-div – 1 ms PWM filter

Using 64 kHz PWM requires putting the timers in Fast PWM Mode:

  • Timer 1: Mode 5 = Fast PWM, 8-bit resolution
  • Timer 2: Mode 3

The Arduino code that does the deed:

// Timer 1: PWM 9 PWM 10 - Hall offset
TCCR1A = B10000001; // Mode 5 = fast 8-bit PWM with TOP=FF
TCCR1B = B00001001; // ... WGM, 1:1 clock scale -> 64 kHz

// Timer 2: PWM3 PWM11 - MOSFET gate drive A, B
TCCR2A = B10100011; // Mode 3 = fast PWM with TOP=FF
TCCR2B = B00000001; // ... 1:1 clock scale -> 64 kHz

analogWrite(PIN_SET_VGATE_A,0); // force gate voltage = 0

With that in hand, things look a lot better:

PWM Ripple - 64 kHz 200 mA
PWM Ripple – 64 kHz 200 mA

The oscilloscope scales aren’t the same and the PWM duty cycle isn’t quite the same, but the LED current ripple drops by a little more than the factor of two you’d expect.

The crisp rising edge comes from the analog switch between the PWM filter and the MOSFET gate, plus a bit of code trickery that presets the PWM and lets it ramp up before turning on the gate drive.

I should recompute the voltage-to-current scale factor, but that could rapidly turn into a curve-fitting exercise. It’s pretty close already.

Sencha Green Tea: Japanese vs. Chinese

I recently ordered a pound of genuine Japanese Sencha Green Tea from Harney & Sons (who turn out to be a long bike ride away at the Millerton end of the Harlem Valley Rail Trail), having had entirely enough of the rather bitter Chinese Sencha from the local grocery store.

Guess which one is which:

Japanese vs Chinese Sencha Green Tea
Japanese vs Chinese Sencha Green Tea

Yup, Japanese on the left, Chinese on the right. The latter comes from the bottom of the container, hence the larger proportion of flakes, but it’s obviously different stuff.

Based on the first few cups, the new tea has a much better taste.

From what I read, the price of Japanese teas has taken a real beating in recent years, because everyone (else) fears Fukushima Daiichi fallout. My feeling is that a Chinese tea plantation could be downwind of Smiling Face Heavy Metal Refinery Complex Number 5 and you’d never know it.

For reference, the Japanese Green Sencha was $40 for 1 lb delivered.

They tossed in a few sample packets, including “Paris: Black tea with Fruit and Caramel”, which was horrible…