Gas station without pumps

2019 December 28

Holiday activities

Filed under: Uncategorized — gasstationwithoutpumps @ 21:28
Tags: , , , , , , , , ,

We celebrated several holidays over the past week: Festivus, Christmas, and Chanukah. We neglected Solstice this year (most years we make solstice cookies).

For Festivus, we put up a Festivus pole and ate meatloaf on iceberg lettuce (well, vegetarian meatloaf, since my son is a vegetarian).  We skipped the airing of grievances, though.

On Christmas Eve, we went out to eat, but almost all the restaurants downtown were closed (even the Chinese restaurant that we had considered as a backup), so we ended up at the Korean restaurant Sesame.  My wife and I enjoy the food there, but there is not a lot for our vegetarian son—he was ok with the japchae, but I could tell he was a little sad that both Saturn and Monster Hotpot were closed.

For Christmas we had a live Christmas tree (the same one as last year, but it is now 22 inches tall—plus a 12 inch pot), which my wife decorated with a small fraction of our Christmas ornaments. This tree has many years before it is the size of the live trees we used to use, but we can carry it into the house with needing a hand truck. (The big one that we gave away a couple of years ago was getting to be too heavy to haul up the 3 steps to the porch.)

We also opened presents from each other Christmas morning.  Most of the presents were books or consumables—we’re all hard to shop for as we don’t want much, and when we do want something, we generally just buy it for ourselves.

For Chanukah we lit the candles on the menorah each night and had homemade applesauce and latkes one night.

Over the winter break, I’ve been getting several things done:

  • I got the syllabus rewritten for my electronics course, got the assignments all entered into Canvas (which always takes forever—filling out the same form over and over is incredibly tedious), and hired my group tutors and graders.  Creating the Canvas entries for the due dates for the 12 homeworks, 6 prelabs, and 5 labs took a couple of hours, and I still have to enter the quizzes (which I’ll do after I’ve created and graded each quiz, as each will have a different number of points).
  • The cat fountain I created failed, and I spent some time trying to diagnose the problem.  The controller board is fine, but the pump won’t run.  The resistance of the pump is now about 100kΩ, which indicates that something in it failed.  I’m not sure of the reason for the failure, but most likely the impeller was jammed by a build-up of algae.  The cats were less interested in the fountain than I hoped, and keeping the cat fountain clean was more trouble than I expected (algae growth was fast, and clearing the hose with a pipe cleaner was a pain), so I decided to scrap the fountain, rather than buying another pump.
  • The mesh seat that I sewed for my recumbent bicycle five years ago had the stitching fail on one strap. I tried resewing it with my wife’s sewing machine, but it just jammed, so I ended up resewing the strap by hand.  I expect that some of the other stitching will fail in the next year, and that I’ll be doing more resewing, but there is enough redundancy in the straps that I can ride home even with one of the straps broken.
  • My son visited Monday–Friday, so we spent a couple of days installing the new range hood that I had promised my wife six months ago.  I bought a 2-part range hood ( with the blower unit to be installed in the attic, even though this is more expensive than one-piece units.  There were two reasons: to make the range hood itself lighter and so easier to install, and to reduce the noise of the blower in the kitchen.  Holding up even the motor-less range hood while we got the screws in place was tiring (for my son), but installing the blower in the attic was also somewhat difficult, so that was pretty much a wash.  The new range hood is much quieter than the old one, but I think it moves as much air.  At any rate, my wife is pleased with the new range hood, which is all that really matters.

Mostly, though I’ve been reading and sleeping—things I’ll have much less time for once the quarter starts. I do still have to write the quiz for the first week of class, but I still have a week to do that.

2019 September 1

Cat drinking fountain completed

Filed under: Uncategorized — gasstationwithoutpumps @ 13:38
Tags: , , ,

In Beginning design of a cat drinking fountain I wrote

One of our cats likes to drinking from running water (a bathroom sink on a trickle setting), so my wife challenged me to make a drinking fountain for the cat that recirculates water in a water dish.  This project will be mainly physical design (3D printing, gluing things together) with a little electronics to control the pump.

I finished the cat fountain this week—the amazing thing is that I only had to print each part once, with the first design working!  (Well, that’s almost true—I printed a bunch of 2mm-thick test pieces for the hose clip, to try to get something that would hold firmly to the rim of the bowl, and I aborted one print of the hose clip after a couple of layers, when I realized that one part had not been made level on the bed before slicing.)  All the big pieces went together on the first try, and the first fully printed hose clip worked.

Unfortunately, the cats have not show any interest in the fountain yet.

Here is a top view of the fountain running. The rocks serve two purposes—to make the fountain quiet (avoiding the trickling noise of faucet left running) and providing some weight to keep the bowl from tipping. I don’t know whether the weight is enough if a cat rests both front paws on the rim—that has not been tested yet.

Here is a side view of the fountain, showing the base with the control knob for adjusting the flow rate.

Here is a side view of the fountain, showing the hose clip, which is glued together from two pieces, to avoid having to print any overhangs. The rounded-triangle bolt holes are visible on the side of the base.

Here is a bottom view of the fountain, showing the barrel jack for power, the support for the pump, and the hose from the pump.

Here is a top view of the base, showing how it is divided into 4 parts so that each part is small enough to be printed in the 110mm-diameter print area of the Monoprice Delta Mini. The parts are bolted together with M3-18mm bolts

I printed a nozzle for fountain also. I’ve been thinking of printing some other nozzle shapes, to see what produces the nicest stream. I was pleased by how well the nozzle fit into the ¼” ID hose—I had expected to end up with something either too large to fit or with barbs too small so that the nozzle fell out, but everything worked ok.  I would make the barbs slightly larger if I wanted something that would hold under pressure, though.

I’ve started using rounded-triangle holes for horizontal bolt holes.  The edges of the holes are three circular arcs, with the centers of the circles at the points of an equilateral triangle, and the radius being the side length of the triangle.  I make one of the vertices be in the positive z direction.  The arched shape is a little easier for the printer to print than the flat top of a circular hole, though for holes this small even circular holes print ok.

I designed in a little clearance between the parts, so that I would not need to sand things to make them fit.  The 0.15mm clearance I allowed seems to be about right—the pieces bolted together without problems and the fit seems to be pretty tight.

I drilled the melamine bowl with a 3/8″ Forstner bit, as that seemed to be exactly the right size for the 9.5mm inlet of the pump. Before drilling with the drill press, I covered both sides of the bowl where I was going to drill with transparent tape and taped a piece of MDF below the bowl to support the surface.  I got no cracking and the pump outlet fit tightly in the resulting hole.  I glued the pump to the bottom of the bowl with FlexEpox, which I also used to glue the two halves of the hose clamp together.

The controller is the design I used for the desk lamps—I happened to have one sitting around unused.  I didn’t even change the code, though I’ve been thinking about changing the range of the PWM, and possibly raising the PWM frequency. The pump sometimes makes a quiet, but slightly annoying noise at about 2.2kHz when set to low flow rates. The PWM frequency is nominally 2.344kHz at low output and 9.375kHz at high output (with a 9.6MHz clock), and the 2.2kHz sound is within the ±10% spec for the RC oscillator in the ATtiny13 chip.  I may not need as high a precision at low levels for the motor as I do for LEDs, so a simpler program that just uses a 256-step PWM at around 9kHz may be better.

A capacitor across the motor may also help to reduce the voltage fluctuation that causes the noise.  If the motor is drawing about 300mA and the power is off for about ¾ of the period (at 2.2kHz), then we’d need about 100µC from the capacitor.  If we want the voltage to drop 9V in that time, the average voltage is 4.5V and a 22µF capacitor would be about the right size.  Of course, I’d have to go to lower duty cycles, as the average voltage across the motor would be much higher than without the capacitor. Even very short duty cycles may not be low enough, as the capacitor charges very quickly and the slow discharge may leave the pump running at too high a speed—in that case I’d need to make the capacitor smaller.

(Update 2019 Sept 1: a 10µF ceramic capacitor does seem to quiet the 2.2kHz sound while still allowing the motor to be turned down to the point where it stalls. Of course, my tinnitus is loud enough that the fountain may still be making noise, but I just can’t hear it over the tinnitus.)

(Update 2019 Sept 9: the pump was still whining, even with the capacitor, so yesterday I did the right thing and reprogrammed the ATTiny13 in the controller to use a PWM of ~37.5kHz, instead of 2.2kHz.  The cats may still be able to hear it, as the cat range of hearing is about 48Hz–85kHz [], but I can’t hear it.)

The fountain takes about 2–3W (measured at the AC input to the power supply), so I’ve not looked into adding a power switch or a motion detector to turn the pump on and off.

As usual, I designed everything using OpenSCAD.


// barbed nozzle(s) for pump
// Kevin Karplus
// 2019 August 12
//  Creative Commons Attribution-ShareAlike  (CC BY-SA 3.0)

module nozzle(ID=3, OD=6, final_OD=undef, length=undef, num_barbs=undef)
    $fa=5; $fs=0.1;
    barb_diam= 1.15*OD;
    barb_length= OD/3;

    assert(num_barbs!=undef || length!=undef);
    barb_count = num_barbs!=undef? num_barbs: max(1, min(4, length/barb_length -2));
    real_length = length!=undef? length: (barb_count+1)*barb_length;
    real_final_OD = final_OD==undef? OD: final_OD;
    flare_from = (barb_count+1)*barb_length;
    assert(flare_from < real_length || OD==real_final_OD);
    barbs = [for (i=[1:barb_count]) each [[barb_diam/2, i*barb_length], 
                                [OD/2, i*barb_length]] ];
    profile = concat( [[ID/2,0], [OD/2,0]], barbs,
        [   [OD/2, flare_from],
    {    polygon(profile);


    color("red")    nozzle(length=20, num_barbs=3, final_OD=10);
    color("blue",0.4) translate([0,-12,0]) rotate([30,0,0]) cube(36,center=true);


// cat dish hose clip
// Kevin Karplus 2019 Aug 25
//  Creative Commons Attribution-ShareAlike  (CC BY-SA 3.0)

// v1 uses linear_extrude for bowl rim, has wrong rim profile
// v2 uses rotate_extrude for bowl rim, rim profile angled wrong outside, too wide
// v3 has taller clip.  Rim profile is better, but still not right.
// v4 tweaked the rim profile, but still a little loose
// v5 tweaked the rim profile some more, but apparently in the wrong direction
// v6 seems to have an ok rim profile, though clipping it on the rim opens the 
//    fork a bit, so that the rim is only grasped near the top.

use <BOSL2/std.scad>
include <BOSL2/paths.scad>
include <BOSL2/rounding.scad>


$fa=0.3; $fs=0.1;

bowl_diam = 254;    // bowl diameter at rim

// rim profile
inside = [ [0,0], [-2,0], [-3,-0.3], [-4,-1], [-5.1,-2],  [-6.6,-4],
    [-7.2,-5], [-10,-10], [-16,-20], [-22,-30]];
L2 = reverse([for (pt=inside) pt+[0,3.4]]);
outside =  [ [0,0], [-1.9,-0.9], [-2.8,-1.4], [-4.7, -2.8], [-5.5,-3.5],[-6.5,-4.6],[-10,-9.9], [-13.6,-15], [-18.1,-21.6], [-22.3,-27.8], [-26,-33.6]

L4 = simplify2d_path(concat(outside,[outside[len(outside)-1]+[1,-3]], reverse(offset(outside,5)), 
        [[5,-5], [5,9]], 
        reverse(offset(L2,5)), [L2[0]+[-3,-1]], L2 , [[0,0]] ));

module rotate_extrude_at_origin(r=bowl_diam, arc_l=12)
// like linear_extrude but curving the extrusion by
// rotating about x=-r, to get an arc length of arc_l for point at origin
    angle = arc_l/r*180/pi;
    translate([-r,0,0])rotate_extrude(angle=-angle) translate([r,0]) children();

module hose_clip(clip_thick=12)
    r= bowl_diam/2;
    angle = clip_thick/r *180/pi;
       color("blue")rotate_extrude_at_origin(r=r, arc_l=clip_thick)
        {  polygon(L4);
        translate([-r,0,0]) rotate([0,-angle/2,0]) translate([r,0,0])
        {    translate([0,20,0]) rotate([0,90,0]) cylinder(d=9, h=11, center=true);
            translate([0,25,0]) cube([11,10,7.5], center=true);

module split(r=bowl_diam/2, arc_l=clip_thick, move_to=[15,0])
// split the children at the a plane through x=-r, with angle top_angle/2
//  to the xy plane, rotating so that top_angle is on xy plane, and
//  moving it over to move_to
    // below cut plane
    {    children(); 
         rotate_extrude_at_origin(r=r, arc_l=arc_l/2)
          { translate([-r+0.001,-2*r]) square( [4*r,4*r]);
    // above cut plane
    top_angle = arc_l/r *180/pi;
        rotate([0,180,0])  // rotate so top surface is now on bottom
        translate([0,0,-r*sin(top_angle/2)])  // top is xy plane
        rotate([0,top_angle/2,0])  // top is horizontal
    {   color("red") translate([-r,0,0]) rotate([0,top_angle/2,0]) translate([r,0,0])
        rotate_extrude_at_origin(r=r, arc_l=arc_l/2)
        { translate([-r+0.001,-2*r]) square( [4*r,4*r]);

// test rim shape
// hose_clip(2);

split(arc_l=clip_thick) hose_clip(clip_thick);


// Base for running-water cat bowl
// Kevin Karplus 2019 Aug 24
//  Creative Commons Attribution-ShareAlike  (CC BY-SA 3.0)

// First some measurements and model for the pump
    wire_h = 15;

module pump()
{   $fa=4; $fs=0.1;
    cylinder(d=pump_d, h=pump_h-4);
    cylinder(d=21, h=pump_h);
    cylinder(d=9.5, h=35.7);
         cylinder(d=outlet_d, h=10+pump_d/2);
    rotate([0,0,135+8.5])  translate([10,0,-wire_h]) 
    rotate([0,0,135-8.5])  translate([10,0,-wire_h]) 

// how much space should be left between matching surfaces?
clearance = 0.15;

module nth_circle(diam=127, thickness=18, arc=120)
// draw a part of a circular arc (no more than 180 degrees)
// with outer diameter diam and inner diam diam-2*thickness
{   $fa=1;
        {     circle(d=diam);
        polygon(scale*[[0,0], [1,0], 
                [cos(arc/2), sin(arc/2)],
                [cos(arc), sin(arc)]

module overhanging_circle(arc=120, diam=127, outer=10, inner=8, overlap_degrees=20)
// Two circular arcs offset from one another, with thickness "outer"
// for the outer arc and "inner" for the inner arc.
// The outer arc starts on the x-axis, the inner one at "overlap_degrees".
        nth_circle(arc=arc, diam=diam, thickness=outer-clearance/2);
    mid_diam = diam-2*outer-clearance;
        nth_circle(arc=arc, mid_diam, thickness=inner);
        nth_circle(arc=arc-overlap_degrees, diam, thickness=inner+outer);
    echo ("max_dist = ", 0.5*norm([diam,0] - diam*[cos(arc),sin(arc)]),
          "or",  0.5*norm([diam,0] - mid_diam*[cos(arc+overlap_degrees),sin(arc+overlap_degrees)]) );

module rounded_triangle(side=1)
// intersection of three circles, centers at corners of equilateral triangle.
// On corner is on x axis.
{    intersection()
    {   translate([side/sqrt(3),0]) circle(r=side,$fn=60);
        translate([-side/(2*sqrt(3)), side/2])  circle(r=side, $fn=60);
        translate([-side/(2*sqrt(3)), -side/2])  circle(r=side, $fn=60);

module rounded_beam(side=1, length=3, center=false)
// rounded_triangle beam from (0,0,0) to (0,0,length). 
// (0,0,-length/2) to (0,0,length/2) if center is set.
// Corners of beam as for rounded_triangle.
{    linear_extrude(height=length, center=center) rounded_triangle(side=side);

module screw_hole(side=3.5, cap_side=6, cap_depth=4, length=18)
// rounded_triangle screw hole, for horizontal screw holes
// Top of screw_hole at x=0, screw extends length+cap_depth along -x axis.
// Hole is oriented so that point of arch in +z direction.
// Default sizes are appropriate for M3 screws.
    rotate([0,-90,0])  // put beam along negative x-axis
        rounded_beam(side=cap_side, length=cap_depth);
        rounded_beam(side=side, length=length+cap_depth);

module drilled_overhang(arc=90, diam=127, outer=10, inner=8, overlap_degrees=10,
    height = 40,
    hole_d=3.5, cap_diam=6, cap_depth=4)
// make a part of the circular wall, with screw holes to line up sections
{    assert (outer> cap_depth+3, "Outer wall thick enough for screw hole");
    clearance_angle = atan(2*clearance/diam);
    {    linear_extrude(height)
            overhanging_circle(arc=arc-clearance_angle, diam=diam, 
                outer=outer, inner=inner, 
        for (angle= [overlap_degrees/2, arc+overlap_degrees/2])
            for (z= [height/3, 2*height/3])
                translate([0,0,z])      // move beam up
                rotate([0,0,angle]) // put beam in correct orientation
                translate([diam/2+0.001,0,0]) // move out to circle
                    cap_side=cap_diam, cap_depth=cap_depth, 

module controller_board()
// cut this module out of a drilled overhang to make room for the
//	controller board
    $fa=2; $fs=0.1;
    length= mid_length+ width;
    linear_extrude(2*height) polygon([ [length/2,0],  //point
        [mid_length/2,width/2], [-mid_length/2,width/2], // mid-length side
        [-length/2, width/4], [-length/2,0],  [-length/2, -width/4],// spread point (for wires)
        [-mid_length/2,-width/2], [mid_length/2,-width/2]
    cylinder(d=8, h=32);
           screw_hole(side=3.5, cap_side=6, cap_depth=4, length=18);
           screw_hole(side=3.5, cap_side=6, cap_depth=4, length=18);

module controller_panel(arc=110)
// minor bug:  the top edge has a cantilevered part that barely works---
//	the first layer of the cantilevered part does not bond to the
//	subsequent layers.
//      Possible fixes include removing the cantilevered part (cutting
//	the top back to just the front face, as was done on the power panel)
//	or tapering the cantilever so that it has a 45-degree slope to it.
    {   overhang=10;
            rotate([-90,0,0])  // make up be +y direction
            translate([0,35+35+22,20]) cube(70,center=true);

module notch_panel(arc=80,height=40, diam=127)
// minor bug: the notch could be just a little tighter to
//  grasp the 1/4" ID vinyl tubing, rather than having it resting loose in
//  the notch.
    {   drilled_overhang(diam=diam,arc=arc,overlap_degrees=10);
        {   translate([0,-hose_d/2,0]) cube([diam+1,hose_d,hose_d+1]);
            rotate([0,90,0]) cylinder(d=hose_d,h=diam+1, $fs=0.1);

module pump_panel(arc=90,height=40, diam=127)
// Bug:  There is nothing in this version to keep the pump from sliding off 
// the platform if the base rotates—a rim is needed around the pump.
// Minor bug: the platform is a little too high, as there was not enough
// clearance for the wall of the hose between the outlet of the pump and the 
// bottom of the bowl.

    platform_h = height-pump_h;
    scaled_offset = offset/ (pump_d/2);
    tangent1 = [cos(180+alpha),sin(180+alpha)];
    tangent2 = [cos(180-alpha),sin(180-alpha)];
         color("blue")  drilled_overhang(arc=arc,overlap_degrees=10, height=height);
        {   pump_angle=135;  // rotation to align outlet with notch
            {   cylinder(h=platform_h, d=pump_d, $fs=0.1, $fa=1);
                color("cyan") linear_extrude(platform_h) polygon(
                     10*[cos(135+pump_angle), sin(135+pump_angle)],
                     // tangent1*pump_d/2,

            // notch for pump wires
            rotate([0,0,135+pump_angle]) translate([10+1.8,0,0])
                cylinder(d=7.2,h=3*platform_h, center=true, $fa=1, $fs=0.1);
            // ghost of pump to check alignment---not part of model
            % translate([0,0,platform_h]) rotate([0,0,pump_angle]) pump();

module power_panel(arc=80,diam=127,height=40)
// minor bug:  the hole for the socket for barrel adapter is 
//      slightly too small.
//      The socket can be screwed into the hole, but not slid in.  
//      Slight sanding with a riffler was enough to fix the problem.
    outer_face = diam/2-1;
    wall_t = 5;
    cut_w = 16;
    {   overhang=10;
        {  translate([0,0,height/2]) 
              rotate([0,90,0])  // drop into +x direction
                  cylinder(d=7.7, h=diam/2+1, $fs=0.1);
            translate([outer_face,-35,0]) cube(70);  // outer face
            translate([outer_face-wall_t-cut_w, -cut_w/2, 0]) // inner face

// comment out all but one panel for making STL files
 color("red") rotate([0,0,90])notch_panel();
 color("green") rotate([0,0,170]) controller_panel();
 color("purple") rotate([0,0,280]) power_panel();

2019 August 14

Beginning design of a cat drinking fountain

Filed under: Uncategorized — gasstationwithoutpumps @ 22:11
Tags: , , ,

One of our cats likes to drinking from running water (a bathroom sink on a trickle setting), so my wife challenged me to make a drinking fountain for the cat that recirculates water in a water dish.  This project will be mainly physical design (3D printing, gluing things together) with a little electronics to control the pump.

I started by buying a very cheap pump from American Science and Surplus: an ET 23 series pump that they are getting rid of for only $2.50.  Somewhat surprisingly, there is a data sheet available for this pump from the manufacturer:, but (not so surprisingly) the specs are different from what American Science and Surplus claims. The manufacturer says that the pump is submersible and can be run at 5V to 12V, while American Science and Surplus says it is not submersible and runs on 4V to 6V.  Because the pump electronics are fully potted, I tend to believe the manufacturer on this one.

The pump uses a brushless motor with two sets of windings (and only 2 transistors to power them) and seems to start pumping at about 4V.  To characterize the pump, I used my Analog Discovery 2 to sweep the power-supply voltage from 0V to 10V, measuring the current through a 0.5Ω resistor.  The results were interesting:

At low voltage, the current seems to be exponential with voltage, as would be expected from having a diode in the circuit—the nonideality of 5.6 is consistent with about 3 silicon diode drops. Above 4V, the motor behaves about like a 26Ω resistor, though with a lot of noise. The turn-on and turn-off behavior between 2V and 4V is interesting—the pump takes a lot of power at these voltages. All these measurements were taken with the pump running dry—it likely behaves differently when pumping water.

The “noise” in the I-vs-V curve is not random noise—it is fluctuation in the amount of current taken as the circuitry for the brushless motor switches between the two sets of coils. If we set the power supply to a constant 5V across the motor in series with the 0.5Ω resistor, we can observe the voltage and the current for the motor:

The two coils seem to take slightly different peak currents when the switch for them is turned on, but both spikes are about 2.8 times the average current. The frequency is around 643 Hz, which implies a speed of around 19300RPM.

I tried controlling the pump with one of the PWM LED controllers that I made for the desk lamps. With a 6V power supply, I need about 60% duty cycle to start the motor, but then can turn it down to about 15–20% duty cycle.  With an 8V power supply, I need about 40% to start and with a 10V supply about 30% to start. All these were crude measurements by turning a potentiometer until the motor started, but they are consistent with about a 3.3V average starting voltage and ability to keep running down to almost 1V.  If the pump stalls at low voltage, one has to bring it up to about 3.5V to turn it back on.

The motor runs even with fairly slow, low-duty cycle PWM. The current spikes at the beginning of each cycle are large.

The PWM control seems to work even with a PWM frequency as low as 270Hz, which is somewhat surprising.  There does not seem to be much in the way of voltage spiking, even with no capacitor or flyback diode added.  There is a short-lived initial current spike of about 3.5A (staying above 2A for about 4µs), which probably comes from charging capacitor C3 in the motor, which is across the power lines after the diode D1 (which seems to be there to prevent reversed power supply).  The 11µC spike is consistent with C3 being about a 1 µF capacitor (or maybe 2.2µF), which seems plausible.  I’m not sure why the current drops to 0 before the motor voltage drops more than about a volt.

I bought some cheap plastic bowls from a thrift store, and my next task is going to be to design a 3D-printed base to hold the pump and the electronics under the bowl and a clip to hold a ¼” ID vinyl tube over the bowl.  The pump is not self-priming, so I need to drill a hole in the bottom of the bowl and glue on the pump to make a gravity feed to do the priming.

%d bloggers like this: