Archive for category Software
As part of some protracted flailing around while trying to get GNU Radio running on a Raspberry Pi 3, I discovered Raspbian defaults to a 100 MB swap file, rather than a swap partition, and everything I though I knew about swap management is now inoperative. The key hint came from some notes on
/etc/dphys-swapfile config file to set
CONF_SWAPFACTOR=2 for a 2 GB swap file = twice the size of the Pi’s 1 GB memory.
Start it up:
sudo dphys-swapfile swapoff sudo dphys-swapfile setup sudo dphys-swapfile swapon
And verify it worked:
cat /proc/meminfo MemTotal: 949580 kB MemFree: 194560 kB MemAvailable: 594460 kB Buffers: 85684 kB Cached: 377276 kB SwapCached: 0 kB Active: 600332 kB Inactive: 104668 kB Active(anon): 250408 kB Inactive(anon): 20688 kB Active(file): 349924 kB Inactive(file): 83980 kB Unevictable: 0 kB Mlocked: 0 kB SwapTotal: 1918972 kB SwapFree: 1918972 kB Dirty: 40 kB Writeback: 0 kB AnonPages: 242072 kB Mapped: 136072 kB Shmem: 29060 kB Slab: 33992 kB SReclaimable: 22104 kB SUnreclaim: 11888 kB KernelStack: 1728 kB PageTables: 3488 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 2393760 kB Committed_AS: 947048 kB VmallocTotal: 1114112 kB VmallocUsed: 0 kB VmallocChunk: 0 kB CmaTotal: 8192 kB CmaFree: 6796 kB
Then it became possible to continue flailing …
The folks I’ve been coaching through their plotter build project showed it off at the local MiniMakerFaire this past weekend. Next time around, I’ll insist they secure their circuit boards and use good wiring techniques, so as to avoid destroying more stepper drivers.
To that end, adding mounting holes to my proto board holder seems in order:
The board dimensions now live in an associative array, so you just pick the board name from a Configurator drop-down list:
/* [Options] */ PCBSelect = "ArdUno"; // ["20x80","40x60","30x70","50x70","70x90","80x120","ArdDuemil","ArdMega","ArdPro","ArdUno","ProtoneerCNC"] PCB_NAME = 0; PCB_DIMENSION = 1; PCBSizes = [ ["40x60",[40,60,1.6]], ["30x70",[30,70,1.6]], ["50x70",[50,70,1.6]], ["20x80",[20,80,1.6]], ["70x90",[70,90,1.6]], ["80x120",[80,120,1.6]], ["ArdDuemil",[69,84,1.6]], ["ArdMega",[102,53.5,1.6]], ["ArdPro",[53,53.5,1.6]], ["ArdUno",[69,53.1,1.6]], ["ProtoneerCNC",[69,53.1,1.6]], ];
Which seems easier than keeping track of the dimensions in comments.
You can now put the PCB clamp screws and mounting holes on specific corners & sides, allowing oddball locations for Arduino boards with corner cutouts along the right edge:
A “selector” notation separates the hole location from the board dimensions & coordinates:
ScrewSites = [ // [-1,1],[1,1],[1,-1],[-1,-1], // corners // [-1,0],[1,0],[0,1],[0,-1] // middles [-1,1],[-1,-1],[1,0] // Arduinos ];
Might not be most obvious way, but it works for me. Most of the time, corner clamps seem just fine, so I’m not sure adding the clamp and mounting hole locations to the dimension array makes sense.
The OpenSCAD source code as a GitHub Gist:
Being a big fan of having a CNC machine know where it is, adding endstops (pronounded “home switches” in CNC parlance) to the Mostly Printed CNC axes seemed like a good idea:
All the mounts I could find fit bare microswitches of various sizes or seemed overly complex & bulky for what they accomplished. Rather than fiddle with screws and nut traps / inserts, a simple cable tie works just fine and makes the whole affair much smaller. Should you think cable ties aren’t secure enough, a strip of double stick tape will assuage your doubts.
A snippet of aluminum sheet moves the switch trip point out beyond the roller’s ball bearing:
I’m not convinced homing the Z axis at the bottom of its travel is the right thing to do, but it’s a start:
Unlike the stationary X and Y axes, the MPCNC’s Z axis rails move vertically in the middle block assembly; the switch moves downward on the rail until the actuator hits the block.
Perforce, the tooling mounted on the Z axis must stick out below the bottom of the tool carrier, which means the tool will hit the table before the switch hits the block. There should also be a probe input to support tool height setting.
The first mount fit perfectly, so I printed four more in one pass:
All three endstops plug into the RAMPS board, leaving the maximum endstop connections vacant:
Obviously, bare PCBs attached to the rails in mid-air aren’t compatible with milling metal, which I won’t be doing for quite a while. The electronic parts long to be inside enclosures with ventilation and maybe dust filtering, but …
The switches operate in normally open mode, closing when tripped. That’s backwards, of course, and defined to be completely irrelevant in the current context.
Seen from a high level, these switches set the absolute “machine coordinate system” origin, so the firmware travel limits can take effect. Marlin knows nothing about coordinate systems, but GRBL does: it can touch off to a fixture origin and generally do the right thing.
The OpenSCAD source code as a GitHub Gist:
A reader (you know who you are!) proposed an interesting project that will involve measuring audio passbands and suggested using white noise to show the entire shape on a spectrum analyzer. He pointed me at the NOISE 1B Noise Generator based on a PIC microcontroller, which led to trying out the same idea on an Arduino.
The first pass used the low bit from the Arduino runtime’s built-in
Well, that’s a tad pokey for audio: 54 μs/bit = 18.5 kHz. Turns out they use an algorithm based on multiplication and division to produce nice-looking numbers, but doing that to 32 bit quantities takes quite a while on an 8 bit microcontroller teleported from the mid 1990s.
The general idea is to send a bit from the end of a linear feedback shift register to an output to produce a randomly switching binary signal. Because successive values involve only shifts and XORs, it should trundle along at a pretty good clip and, indeed, it does:
I used the Galois optimization, rather than a traditional LFSR, because I only need one random bit and don’t care about the actual sequence of values. In round numbers, it spits out bits an order of magnitude faster at 6 μs/bit = 160 kHz.
For lack of anything smarter, I picked the first set of coefficients from the list of 32 bit maximal-length values at https://users.ece.cmu.edu/~koopman/lfsr/index.html:
The spectrum looks pretty good, particularly if you’re only interested in the audio range way over on the left side:
It’s down 3 dB at 76 kHz, about half the 160 kHz bit flipping pace.
If you were fussy, you’d turn off the 1 ms timer interrupt to remove a slight jitter in the output.
It’s built with an old Arduino Pro Mini wired up to a counterfeit FTDI USB converter. Maybe this is the best thing I can do with it: put it in a box with a few audio filters for various noise colors and be done with it.
It occurs to me I could fire it into the 60 kHz preamp’s snout to measure the response over a fairly broad range while I’m waiting for better RF reception across the continent.
The Arduino source code as a GitHub Gist:
Configuring the knockoff RAMPS 1.4 board went reasonably smoothly:
The DC (n.b., not an AC) solid state relay in the foreground switches the 20 V laptop supply brick to the RAMPS shield atop the knockoff Arduino Mega 2560, controlled by the
PS_ON pin (black wire), with +5 V from a pin in the AUX header (yellow wire). The SSR includes a ballast resistor limiting the current to 12 mA, with an inconspicuous red LED behind the black dot showing when the output is turned on.
Because it’s a DC SSR, polarity matters: the supply goes to the + terminal, the RAMPS power inputs to the – terminal.
I haven’t applied much of a load to to the SSR, but it works as expected. Define
POWER_SUPPLY 1 and
PS_DEFAULT_OFF so the boards starts up with the SSR turned off, then use
M80 / M81 to turn it on / off as needed.
Remove D1 on the RAMPS board to isolate the Mega power from the +20 V supply. Stuffed as shown, the Mega draws 70 mA from the USB port, although an external 8 V (-ish) supply is always a good idea.
The stepper is a random NEMA 17 from the heap in a mount intended for a DIY plotter. I adjusted the tiny trimpots on all the boards for 400 mA peak = 250 mA RMS into the windings, after finding 250 mApk didn’t produce nearly enough mojo, even for a demonstration:
Just to get it running, I used
DEFAULT_AXIS_STEPS_PER_UNIT = 100 step/mm,
MAX_FEEDRATE 100 mm/s, and (for lack of anything better)
DEFAULT_*_ACCELERATION 1000. Those all depend the torque produced by the motor current, which is still way too low.
The endstops require
I set the
?_BED_SIZE parameters to a generous 2000, with
?_MIN_POS equal to -SIZE/2 to put the origin in the middle where I prefer it, with a similar setting for the Z axis. Obviously, those numbers don’t correspond to any physical reality.
Three little 100 kΩ thermistors sprout from their header and produce reasonable temperatures, although (being cheap eBay parts) they may not match the Type 4 curve. I don’t have any heaters connected. All the over / under temperature lockouts are disabled, because I don’t care right now.
The G-Code parser wants uppercase command letters, which means I get to press the
Caps Lock key for the first time in nearly forever!
The header along the right edge of the board connects to the LCD control board, which is another story.
The diffs for the
Configuration_adv.h files as a GitHub Gist:
The OLED displays on the streaming radio players have SH1106 controllers supported by the Luma library, which works just fine. Digging into the source shows the default SH1106 setup (see the
class spi() at the bottom) uses an 8 MHz clock:
def __init__(self, spi=None, gpio=None, port=0, device=0, bus_speed_hz=8000000, transfer_size=4096, gpio_DC=24, gpio_RST=25): assert(bus_speed_hz in [mhz * 1000000 for mhz in [0.5, 1, 2, 4, 8, 16, 32]])
Alas, the SH1106 doc suggests a maximum SPI clock of 2 to 4 MHz, the latter only with fair skies, a tailwind, and a stiff power supply:
The display doesn’t get updated all that often, so there’s no point in rushing things:
serial = spi(device=0,port=0,bus_speed_hz=1000000) device = sh1106(serial)
They’ve been ticking along without mysterious blanking or mirroring for a bit over two weeks, so I’ll call it a fix.
For reasons undoubtedly making sense at the time, the Google Pixel (and, most likely, current Android devices) don’t support the USB Mass Storage protocol. A bit of poking around suggests the
jmtpfs utility supplies the other end of the Pixel’s Media Transfer Protocol and the process goes a little something like this:
- Once upon a time, create a mountpoint:
- Unlock the phone
- Plug in the USB cable
- Pull down the top menu, tap
USB charging this device
sudo jmtpfs /mnt/pixel -o allow_other,fsname="Pixel"
allow_other parameter sets the directory / file permissions so ordinary users can access the files. The
fsname is just for pretty.
The Pixel’s storage then appears as the awkwardly named
/mnt/pixel/Internal\ shared\ storage/ directory.
Despite being somewhat Linuxy under the hood, the mapped storage doesn’t support the usual filesystem attributes, so don’t try to transfer them with, say,
rsync -rhu --progress /mnt/music/Music\ for\ Programming /mnt/pixel/Internal\ shared\ storage/Music/
When you’re done:
sudo umount /mnt/pixel
This may not be a win over bankshotting off Dropbox or Google Drive, except for sensitive bits like private keys and suchlike.
Thunar apparently knows how to detect and mount
mtp devices automagically and I suppose GUI-fied drag-n-drop works as you’d expect.