Check out my first novel, midnight's simulacra!

A case study in full-stack device development: the dankdryer and Hack on: Difference between pages

From dankwiki
(Difference between pages)
Jump to navigation Jump to search
No edit summary
 
No edit summary
 
Line 1: Line 1:
'''[[Dankblog|dankblog!]] 2024-09-29, 2329 EDT, at [[Viewpoint|the danktower]]'''
__NOTOC__
=='''rien n'est simple, mais tout est facile'''==
[[File:Ourheroreturns.jpg|right|thumb|your humble wikist 2025-06-29]]
this is the wiki of [mailto:dankamongmen@gmail.com nick black] (aka [[User:Dank|dank]]), located at [[LOC record|33°46′44.4"N, 84°23'2.4"W (33.779, 85.384)]] in the heart of [[Atlanta|midtown atlanta]]. dankwiki's [https://www.youtube.com/watch?v=i2tukPoF2ww rollin' wit' you], though i make no guarantees of its correctness, nor its relevance, nor its timeliness. track changes using the [[Special:RecentChanges|recent changes]] page. i've revived [[dankblog|DANKBLOG]], this wiki and [[Grad_school|grad school]] having not satisfied ye olde ''furor scribendi''.


update: this has been [[Dankdryer_improvements|improved]], and improved a bit more than that, and is now [https://dankdryer.com available for purchase]!
hack the planet! don't mistake my kindness for weakness.


[[File:Fullrender.png|renderings made using blender]]
i primarily write to force my own understanding, and remember things (a ''few'' entries are actually semi-authoritative). i'm just a [http://en.wikipedia.org/wiki/The_Rime_of_the_Ancient_Mariner disreputable Mariner] on your way to the Wedding. '''if you derive use from this wiki, consider yourself lucky, and please get confirmation before relying on my writeups to perform surgery, design spacecraft, determine whether a graph ''G'' is an [https://en.wikipedia.org/wiki/Aanderaa%E2%80%93Karp%E2%80%93Rosenberg_conjecture#Deterministic_query_complexity Aanderaa–Rosenberg scorpion], or feed your pet rhinoceros.''' do not proceed if allergic to linux, postmodern literature, nuclear physics, or cartoonish supervillainy. ■


Materials like PA (nylon), PVA, and TPU tend to be fairly hygroscopic, meaning that they collect and retain moisture. It is said that PVA filament can retain more than 10% of its weight in water. Wet filament can ruin a print two ways: hydrolysis reactions break up polymers, rendering filament brittle and negatively affecting its mechanical properties, and moisture can flash into steam in the hotend. Water is many times less dense in its gaseous form, and in the small volume of a hotend, it'll exert tremendous pressure, affecting material flow. Moisture furthermore promotes generation of particulate matter during printing, undesirable for breathing even when it's not explicitly carcinogenic or otherwise toxic.
==[[:Category:Projects|projects?]]==
Nothing that's any good works by itself, just to please you; you've got to make the Damned Thing work.


PLA, PETG, ABS, and ASA will not generally absorb more than ~2% of their weight, but this still results in stringing, zits, and weaker output. Expensive engineering filaments can be rendered completely unusable through exposure to even light humidity. If you're in a humid region, drying your filament is a must. Unfortunately, most filament dryers on the market can't get above 70℃, have a difficult time maintaining even that temperature, and are generally terribly designed. Engineering filaments are best dried using temperatures over 100℃: Bambu recommends 140℃ for their [https://us.store.bambulab.com/collections/pps/products/pps-cf PPS-CF] and [https://us.store.bambulab.com/collections/bambu-lab-3d-printer-filament/products/ppa-cf PPA-CF] filaments. You won't touch this temperature outside of an oven. Blast ovens work well, but are prohibitively expensive. Kitchen convection ovens set to such (relatively) low temperatures tend to control it poorly; just search for "melted spools" to see the results. Even if you don't melt your filament down, you're filling your cooking area with potentially toxic material. Either way, ovens tend to be inefficient, radiating much of their heat away without applying it to the filament.
* Still growing! The world's largest(?) collection of [[computer science eponyms]].
* [[Notcurses]], a library for blingful TUIs and character graphics
* I created and taught CS4803UWS, "[[UNIX Weapons School]]", Summer 2013 at Georgia Tech.
* [[Hackery]]! (projects and open source work). The [[Personal machines|machines]]. Matrix of [[large cases]] and [[Titanium_power_supplies|Titanium PSUs]].
* The [[WORDHORDE]]. Some [[book ideas|books]] I'd like to write. Too many [[morphisms]]!
* An ambitious [[Decay_chart|chart of decays]].
* [[Grad school]] and [[CS GRE]] prep pages. You can't have grad school without [[LaTeX|XeLaTeX]]!
* [[Elemental naming]] and good [[wordlist|words]]. Ramblings on [[Dankblog|DANKBLOG]].
* [[BlackBerry]] crap. F'n [[bookshelves]]. [[PC_Fans|Fans]] from [[Noctua]], of whom I am a fan.
* What does worldwide [[TaB|TaB®]] consumption have to do with [[nuclear weapons]]?
* I found myself playing a lot of [[Pokémon_Go|Pokémon Go]] in 2025, rather to my surprise.
* My grad school [[:Media:CS8803MCAPresentation.pdf|presentations]] tended to [[:Media:CS8803DCPresentationKlaiber.pdf|run slightly]], just a little, [[:Media:CS8803DCPresentationGschwind.pdf|unorthodox]]...
** enjoy the ghastly background of my [[:Media:Libtorque-presentation.pdf|masters thesis]] presentation
** ...yep, [[Trail of Frames|still weird]] (invited lecture for the opening of [https://wiki.freesideatlanta.org/fs/Info Freeside Atlanta])
** professionally weird! [[:Media:Public_LPC2015_-_Dynamic_iSCSI_at_Scale-_Remote_paging_at_Google.pdf|"Dynamic iSCSI at Scale"]] for Google ([https://blog.linuxplumbersconf.org/2015/ 2015 Linux Plumbers' Conference])
** [[:Media:Pwl09.pdf|"Miscompiling Programs with 'Benign' Data Races"]] for [https://www.meetup.com/Papers-We-Love-Atlanta/events/bhvjlpyxnbmb/ Papers We Love Atlanta #9] 2018-10-09
** [[:Media:Multire.pdf|"Efficiently Matching Multiple Regular Expressions"]] for BetterCloud 2013-12-06
** "[https://mdco2.mini.debconf.org/talks/6-notcurses-making-terminals-do-things-that-were-never-intended/ Making Terminals do Things Never Intended]" for [[Debian]] [https://mdco2.mini.debconf.org/ MiniDebConf #2] 2020-11-20
** "[https://nick-black.com/tabpower/notcurses-fosdem-2021.pdf Notcurses: Blingful TUIs and Character Graphics]" for [https://fosdem.org/2021/ FOSDEM 2021] 2021-02-06
** "[https://debconf21.debconf.org/talks/3-proposing-a-new-d-i-disk-preparation-tool-growlight/ Proposing a New D-I Disk Preparation Tool]" for [https://debconf21.debconf.org/ DebConf21] 2021-08-28
** "[[:Media:Black - Fast Linux Networking 2023.pdf|Fast Linux Networking: DPDK and XDP]]" for Microsoft Azure Orbital 2023-02-03
** "[[:Media:Self-publishing_and_nuclear_secrets.pdf|Self-publishing and nuclear secrets]]" 2024-01-27 release party for <i>[https://midnightssimulacra.com midnight's simulacra]</i>
* My video channel, [[DANKTECH]].
* Other people's [[repositories|projects]]. Other people's [[programming quotes]].


Beyond drying, it is sometimes desirable to [https://blog.prusa3d.com/how-to-improve-your-3d-prints-with-annealing_31088/ anneal] a print following completion. Annealing temperatures tend to run with drying temperature (technically, you want the material's glass transition temperature), and thus a higher-power device can be useful after the print as well.
==unix==
[[File:LookForAnswers.jpg|right|thumb|link=https://nick-black.com/dankwiki/images/5/5b/LookForAnswers.jpg|i like to stay up late on the computer, looking for answers.]]
* Writing high-performance, scalable [[Fast UNIX Servers|UNIX system applications]] is my greatest passion.
* [[Linux APIs]], [[FreeBSD APIs]], [[ELF]] (which is not, in itself, an API).
* [[Power Management]]. [[Sound Software]], [[Using Unicode]].
* Keeping FreeBSD [[Updating FreeBSD|up-to-date]]. Hacking [[CUDA]] on [[Debian]].
* [[Debian]], [[Xorg hell]], [[Consoles]] and [[Framebuffer|Framebuffers]]. [[Systemd]] and [[DBus]]. Making graphs with [[dot]].
* Notes on [[MediaWiki editing|editing]] and [[MediaWiki|running MediaWiki]]. [[Core]] files happen when one dances fandango on [[core]].
* Notes on [[subversion]], but my biggest note would be to use [[git]].
* [[Linux on Dells]], [[SMART]] and [[SATA]], [[udev]], various linux-related [[hardware detritus]] (mainly random personal crap).


I set out to build a better filament dryer. I wasn't designing for mass manufacture, but I did concern myself with printability, ease of assembly, and repairability. I wanted it capable of 150℃, safe with regards to both heat and electricity, and efficient. And dank. This project is and always will be Open Source. Models and firmware are available on [https://github.com/dankamongmen/dankdryer GitHub]. I've provided links to datasheets for each IC; <b>read these datasheets</b> if you intend to build something similar.
did autistic people design this software? BECAUSE I'M STARTING TO LOVE IT.


==Requirements==
==remarks regarding computers &c==
* The device must provide even heating up to 150℃ to the spool, at a constant temperature.
* [[glibc]], other [[interesting libraries]], [[working with libraries]], some implementing interfaces like [[pthreads]].
** The device must not deform or fail under such temperatures.
* [[X Macros]], [[ISO C18]], [[rpaths]], [[GCC|gcc]] notes, [[GNU Make|gmake]] notes.
* Moisture ought be removed from the device.
* a [[Book_list_for_streetfighting_computer_scientists|book list]] for streetfighting coders
* The device must acquire and maintain connection to a preconfigured WiFi network, get a DHCP lease, and announce mDNS.
* There's [[Buses and Ports]], of course, of course.
* The device must be controlled, and report status/measurements, using HTTP and/or MQTT.
* Intel's [[Sandy Bridge]] and [[Nehalem]] x86 [[microarchitectures]].
* The device must be powered by AC mains.
** or, if you'd prefer, [[Transmeta|Transmeta's]] or [[Tilera|Tilera's]] processors.
* The device must measure internal humidity and temperature.
** It's dangerous to go alone! Take [[microcode]].
* The device ought measure weight of the spool, ideally with accuracy within 1% (10g at 1kg).
* The [[cpuid]] instruction, [[SMP on x86]], [[Performance Counters]], [[simulators]].
* The device ought support OTA, with custom data persisted across the update.
** Simulators ought not be confused with the [[4000 Linux VT Solutions|4,000 Linux VT Solutions]]!
* Getting into [[ARM]] (which is everywhere, including [[Raspberry Pi|Raspberry Pis]]).
* Getting into [[ACPI]]. Getting into [[Arduino]]. Getting into [[Architecture]].
** I want a (PIVT, middle-endian, 27-bit word) MISD machine; until then, there's [[SIMD]].
* [[Lamport's Hash]], [[Skip Lists]], I will put thoughts about [[automata|automata here]], [[Dijkstran Method]].
* [[ROS]] seems a pretty good way to write robots, and one day automate luvvvvv
* [[Flash]] sucks. Need get a handle on [[Compiler Design]] by tomorrow's midterm.
** Now it's [[Programming Language Theory]] by tomorrow's final, heh.
* [[Trees]] for smoking and computing. [[Lock-free algorithms|lock- and wait-free]] algorithms. [[Cache-oblivious algorithms]]. [[RCU]].
* [[Allocators]] get us that free store, son (usually through a [[DRAM]]-backed VM)!
** Said VM ''might'' implement [[transactional memory]], and ''almost certainly'' works on [[pages]].
* Via [[Grover's Algorithm]], we might be able to discover the monster at the end of this quantum book.
* While we're at it, [[timer wheels]] and even [[x86 timing]].
* Let's get bipartite, bipartite...with [[bip buffers]].
* I don't much care for writing [[Gecko Addons]] (aka [http://www.mozilla.com/en-US/firefox/upgrade.html FireFox plugins]).
* [[Blum's axioms]] and [[Rice's Theorem]] are both named after people smarter than me...
** ...as are [[Chaitin's Constant]] and [[Kolmogorov complexity]], and [[Computer science eponyms|lots of other junk]].


===Stretch goals===
==networking==
* The device ought read spool RFID tags, and when possible schedule optimal drying parameters.
* Please adhere to the various [[Standards#Networking_standards|standards]] (even where [https://en.wikipedia.org/wiki/Base64#Variants_summary_table mutually contradictory])
* The device ought, upon recovery from power loss, continue the drying operation.
** As one judge said to another, '' 'Be just, and if you can't be just, be arbitrary.' ''
* [[Topology Discovery]]. Online tools for [[Internet analytics]].
* [[SSHFP]] and [[LOC record|LOC]] records. [[DNSSEC]]. The Sender Policy Framework ([[SPF]]). [[VoIP]] and telephony, NAPTR records.
* Some [[TCP]] notes. [[Syncookies]]. Radio of the [[SDR|software-defined]] kind.
* [[ARP]] is no longer used in [[IPv6]], which more fully embraces [[Zeroconf|zero-configuration networking]].
* [[ICAP]] page. [[Tunneling]] (perhaps over [[VXLAN]]), [[SNMP]], [[NFS]]...
* I don't drive, but when I do, I drive via reverse engineered [[CAN bus|CAN buses]].
* [[QMI]] replaces the venerable Hayes command set aka "AT commands" for modems
* [https://nick-black.com/BIginternet Mirror] of the BIg-Internet list from ftp://munnari.oz.au
* [[Van Jacobson Channels]] get everybody all [[DPDK|hooting]] and [[XDP|hollaring]] every decade or so.
* My FCC callsign is [https://wireless2.fcc.gov/UlsApp/UlsSearch/license.jsp?licKey=5060966 KQ4ZNN].


==Macrodesign==
==QEMFD! ([http://en.wikipedia.org/wiki/Q.E.D. wikipedia], [http://mathworld.wolfram.com/QED.html wolfram]) also provides...==
The dryer will be printed, rather than cast from metal or injection moulded, because I have access to a good [[Bambu Carbon X1C|3D printer]]. Most electronics have difficulties working over 60℃, let alone at 150℃, so I need to keep them thermally isolated from the heating area. This suggests a two-chamber design. Unless one uses a circular heating element, the spool must be rotated for even heating. Filament dryers usually stand the spool up, but I want to lay it down, figuring it would be easier to rotate this way (plus harder to knock over) at the cost of occupying greater area. Having decided this, a hot box atop a cool chamber is an obvious choice. I want fans, both to actively cool the electronics, and to remove moisture cooked out of the filament. Intake of the exhaust is undesirable, so fans need to be on different sides of the device, and I'll need air to flow up and into the hotbox from the coolbox. Given the need for thermal isolation, there will be a divider between the two chambers. This pretty much mandates printing them as distinct pieces (the dividing floor will otherwise need be printed with supports).
* A page for our 2015 [https://nick-black.com/wedding/ hax0r wedding], the event of the century
** There is no page for our 2020 divorce, natch
* Documentation for [https://www.notcurses.com Notcurses], my poorly-named but always-rockin' console graphics library
* [https://www.dsscaw.com Dirty South Supercomputing], my [[WeWork|Tech Square consultancy]], launched 2019
* The [https://nick-black.com/processorzoo.html Processor Zoo], which has been wildly surpassed by [https://en.wikichip.org/wiki/WikiChip WikiChip]
* [https://www.sprezzos.com SprezzOS], my now-defunct but forever-beloved Linux distribution


Weighing the spool means it must be supported by the load cell. Accurate measurements require minimizing the load on the cell due to other structures, isolating the load cell from heat and airflow (and correcting for them otherwise), and keeping the spool centered. The load cell will thus need be kept in the center of the bottom chamber, ideally high up to minimize load due to spool support. The load cell can't rotate, since it has wires connecting it to the amplifier (and subsequently the MCU). The heavy motor can't be supported by the load cell. A gear will thus be necessary to transfer torque from a motor to the spool platform. So atop the load cell will be a coupling holding a bearing, a gear, and a platform for the spool. These components can all be printed distinctly, and joined together, eliminating the need for supports. The bearing will then sit in the coupling (likewise printed on its own), which will be screwed into the load cell.
still have any [[Questions|questions?]]


1kg spools tend to be about 70mm thick. This suggests use of 80mm fans, especially since I have several [https://noctua.at/en/nf-a8-pwm Noctua NF-A8s] on hand. Each chamber will thus be about 90mm tall. Diameter of the hotbox will need be about 21cm to accommodate typical spools, and it will be a cylinder so that the spool doesn't have room to move. I need to fit an AC adapter, a perfboard/PCB, the central column, and a motor into the coolbox; ideally this won't require more area than the hotbox (I want the AC adapter inside since I'll need run AC to the heating element directly, and don't want to split the dangerous 120V AC outside the device). If the motor is mounted perpendicular to the column, a [https://en.wikipedia.org/wiki/Worm_drive worm gear] will facilitate orthogonal transfer of torque to the central shaft. If the motor is standing vertically, I'd probably want to use a belt.
'''''quod erat motherfucking demonstrandum!''''' ■


Basically, I want something like this (not drawn to scale):
<hr>
[[File:Macrodesign.png|Macro design]]
<div style="text-align: right;">"I have never known a greater monster nor miracle than myself." — Michel de Montaigne</div>


==Parts==
{{#seo:
I wanted to use stuff I already had if it was at all suitable. As a result, my BOM was higher than it ought be, and some parts are probably not the best ones I could have possibly used.
|title=dankwiki, the wiki of nick black
 
|titlemode=append
===Filaments===
|keywords=nick,black,dank,dankamongmen,dankwiki,blackwiki,notcurses,unix,nuclear,supervillain,growlight,omphalos,sprezzos,dsscaw
Of what I had available, polycarbonate and PAHT-CF were the most heat resistant. Both [https://us.store.bambulab.com/collections/pc-tpu/products/pc-filament Bambu polycarbonate] and [https://cdn.shopify.com/s/files/1/0548/7299/7945/files/PolyLite_PC_PIS_EN_V1.1.pdf?v=1640834258 Polymaker PolyLite PC] claim [https://en.wikipedia.org/wiki/Vicat_softening_point Vicat softening points] of 119℃ and melting points well above 200℃ (228 and 260, respectively). [https://us.store.bambulab.com/products/paht-cf Bambu's PAHT-CF] (carbon fibre-reinforced Nylon 12) melts at 225, but doesn't soften until 220. I had a half kilogram of this, plus another half kilogram of [https://atomicfilament.com/products/carbon-fiber-nuclear-nylon Atomic Filament Nuclear Nylon] (cabon fibre-reinforced Nylon 6). I thus used nylon for both chambers, especially as it holds its shape very precisely, allowing close mating of the chambers. I did the other parts with PolyLite PC.
|description=Nick Black of Atlanta and his personal wiki of linux, computers, postmodern literature, nuclear physics, and cartoonish supervillainy.
 
}}
===Rotational/mechanical===
{| class="wikitable" style="float:right; margin: 0 0 1em 1em"
! Screws !! Purpose
|-
| 4x M5x45 || Hotbox→cool chamber
|-
| 2x M3x6 || Buck converter→mount
|-
| 2x M3x8 || AC adapter→mount
|-
| 2x M3x6|| RC522→hotbox exterior
|-
| 2x M3x6 || Thermostat switch→hotbox exterior
|-
| 2x M3x6 || Heating element→hotbox interior
|-
| 2x M3x8 || Perfboard→mount
|-
| 8x M4x8 || 2x fans (4 each)→exterior
|-
| 2x M4x12 || Coupling→brace→load cell
|-
| 2x M4x20 || Load cell→mount
|-
| 6x M3x8 || Motor→mount
|-
|}
 
As noted earlier, I'd be using two [[Noctua]] [https://noctua.at/en/nf-a8-pwm-chromax-black-swap NF-A8] chromax.black 80mm fans. They are in a square form factor, but the actual spinning area is circular, π40² ~= 5026.5mm². I had a pack of 608 bearings, which seemed like they'd work fine; 608 it was <i>(narrator: they would not work, and I upgraded to a larger [https://www.mcmaster.com/products/bearings/bearing-trade-number~6200-2rs/ 6200-2RS] for stability; this required modifying and reprinting the lower coupling)</i>. Finally, I used a Geartisan 12V 5RPM DC motor, by which I was pretty disappointed (it's louder than it seems it ought be, stalls easily despite the very low RPMs, and I can't find an official datasheet).
 
I've included a model for a 6200-2RS bearing, but recommend you unass $2 for a real one.
 
===Electronics===
As noted before, the device is driven off 60Hz 120V AC mains. I need AC for my heating unit, but DC for my electronics, so an AC adapter is required. I had a sleek, sexy 160W 12V adapter on hand, complete with grounding connection and two 12V outputs. One output would go to my motor controller and fans; the other would go to an [https://www.ti.com/lit/ds/symlink/lm2596.pdf LM2596] buck converter for stepdown to 5V.
 
====DC====
For my MCU, I wanted to use the [https://www.espressif.com/en/products/socs/esp32-s3 ESP32-S3], of which I had several in my possession. Like all ESP32s, this is a dualcore XTensa 3.3V SoC with 2.4GHz WiFi and Bluetooth. Were I designing for mass manufacture, I'd certainly want to design a custom PCB, but as a one-off I was satisfied with perfboard and a [https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/hw-reference/esp32s3/user-guide-devkitc-1.html devkit]. I wanted to power the MCU by USB-C, so that I could easily power it from my computer during testing. I would thus need a USB-C connector with pigtails to solder to the LM2596.
 
Rectangular load cells are much cheaper than circular ones, or a collection of point cells, and ought be serviceable so long as the spool is kept centered. Accuracy is inversely proportional to total weight capacity for a given load cell technology, so I went with a 5kg bar cell and an accompanying [https://www.nuvoton.com/resource-files/NAU7802%20Data%20Sheet%20V1.7.pdf NAU7802] 24-bit DAC + amplifier (I went for the NAU7802 over the more common HX711 because it offers an I<sup>2</sup>C interface). The NAU7802 (like the HX711) works better with 5V for analog power, so we'll take a line out to it from the LM2596. An [https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf RC522] reads 15.96MHz RFID. The ESP32-S3 has a builtin chip temperature sensor, and my humidity sensor (a [https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme680-ds001.pdf BME680]) brings another one to the table. Between them, I ought be able to get a reliable temperature for the cool box, necessary for temperature correction of the load cell readings. A [https://www.pololu.com/file/0J86/TB6612FNG.pdf TB6612FNG] motor controller can supply a sustained 1.2A (peak 3.2A) of 12V, while supporting 3.3V logic. I needed two [https://www.digikey.com/en/products/detail/molex/0470531000/2421261 Molex 4-pin connectors] for the [[PC Fans|fans]], using 12V for power and 3.3V for the tach and PWM signal.
 
An ESP32 can peak at 40mA sourced from a pin, but ought be kept at 20mA or below. The NAU7802 and TB6612FNG are both submilliamp devices, and can be easily powered from the ESP32's 3.3V bus and a single pin. The BME680 consumes 20mA peak (when it's turning on its hotplate), and cruises at 12mA if doing gas detection, but needs only microamps for humidity/temperature/pressure. It should be fine. The RC522 is another story, capable of pulling 100mA, and drinking down a meaty 60mA in its steady state. It'll need its own 3.3V power supply, using either a second buck converter off the 12V source or a voltage divider from 5V. If we implement the latter using a 1.5kΩ and 2.2kΩ resistor, we drop to 2.973V, wasting 2.027V (a peak dissipation of ~200mW and typical ~125mW as heat).
 
{| class="wikitable" style="float:right; margin: 0 0 1em 1em"
! Component !! Voltage !! Max mA !! Usual mA
|-
| BME680 || 1.71–3.6 || 20 || <1
|-
| TB6612FNG || 2.7–5.5 || <1 || <1
|-
| NAU7802 || 2.7–5.5 || 2.1 || 2.1
|-
| RC522 || 2.5–3.3 || <b>100</b> || <b>40</b>
|-
| LM35ZD || <b>4–30</b> || <1 || <1
|-
| Fan PWM || 2.5–5 || 5 || 5
|-
|}
 
In the hotbox, I wanted nothing other than a heating element and thermostat. The [https://www.ti.com/lit/ds/symlink/lm35.pdf?ts=1729162432092 LM35ZD] thermostat is rated up to 150℃, unlike the more common DS18B20 (unfortunately, it wants at least 4V, so we can't run it off our ESP32's 3.3V bus. The 5V will be fine, though, and we needn't adjust the output voltage, because the maximum 150C ought be 1.5V). A cheap ceramic rectangular heater generates up to 230℃.
 
In terms of small components, each fan would require a 1KΩ and 3.3KΩ resistor and a 0.1nF capacitor for its tach circuit. We need a 120Ω resistor for the triac. I'd need 7 ring terminals to interface with the AC adapter (4 on the DC side, 3 on the AC side), and a 2-to-4 XHF connector to split the incoming AC live+neutral lines. A grommet would line the hole through which the AC cable entered the device; I had one on hand, but could otherwise have printed one with TPU. The motor controller's TVS diode ought keep the splashback from our motor's inductive load from blowing up our sensitive ICs; likewise the optocoupler for our AC network. We'll need a 2.2K and 1.5K resistor assuming we don't use a second buck converter.
 
====AC====
Whereas the motor simply needs to be turned on at the start of a drying operation, and off at the end (presumably hours later), the heater is another story. I don't want the coarse control (and limited lifetime operations) of a relay; I'd either sacrifice tight control of the temperature, or be switching the relay off and on regularly. At first, I thought I'd control the heater with PWM. Proper multihertz PWM with AC requires a solid state relay plus zero crossing detection. Given the slow transitions between temperatures, however, such fine-grained PWM isn't necessary. An SSR, basically operating as an AC MOSFET, ought suffice, without the limited lifetime of a mechanical relay. The [https://www.mouser.com/datasheet/2/302/BT136-600E-352978.pdf BT136-600E] in conjunction with a [https://www.jameco.com/Jameco/Products/ProdDS/133874.pdf MOC3061] optocoupler look suitable for my needs, with a 1.4V gate voltage, a 10mA trigger current, a 2.2mA holding current, and the ability to shuffle 4A. A 150℃ NC (normally closed) thermostat switch provides a hardware killswitch in the event of thermal runaway.
 
Finally, we need a NEMA AC cable and a 5A inline fuse.
 
Thus, the components (fans/fuse not shown, resistors/capacitors not labeled, relay was not used):
[[File:Components.jpg|a complete set of components]]
 
==Models==
I designed everything in [[OpenSCAD]]. These are somewhat complex models; a recent (2023+) build of OpenSCAD with the [https://github.com/elalish/manifold Manifold] renderer enabled will make your experience much more pleasant. In addition to the printed parts, I modeled the load cell, AC adapter, and motor, so that I could design around them.
 
===Cool chamber===
The cool chamber is a hollow truncated pyramid. There is a circular hole for its fan, and a much smaller circular hole for the AC cable. The top is open save for the four corners, which expose M5 mounts by which the hotbox is joined to the cool chamber. These each recede into the corner, eliminating the need for supports. The AC adapter, perfboard, and LM2596 are mounted to the floor, with four short mounts each. These allow wires to be run underneath the components, and help smooth out any unevenness due to floor warping. The motor is placed atop a tall mount, and affixed with six M2 screws to a cojoined front plate. The load cell is joined to a smaller mount; this mount does not run its full length, as the load cell needs be able to dip on one side. Two channels run along the sides to guide wires running to the AC adapter. The intake fan is mounted on the outside. The floor is beveled to help fight warping. Incoming cool air runs directly over the perfboard and buck converter, around the load cell's air shield, over the AC adapter, and up into the hotbox.
 
A small inlet is cut into the top opposite the intake fan for the exhaust fan's wires.
 
Note that the optocoupler+triac and RFID reader have no mounts; they are instead mounted to the underside of the hotbox. Hopefully this won't be too hot for their reliable function: we'll have to test and see. The RFID reader ought work across 50mm.
 
[[File:Croom.png|the cool chamber]]
 
===Hotbox===
The hotbox is fundamentally a cylinder circumscribed by an octagonal prism with four half-pyramid mounts by which it is joined to the cool chamber. A hole is cut away from the floor in which the thermocouple sits, exposing its terminals into the cool chamber. More importantly, this allows us to solder the AC circuit externally to the hotbox—we don't want wires running along the hotbox floor! Mounting points similarly exist for the relay and RFID reader, which will be mounted upside-down to the underside. The heater will actually be mounted in the hot chamber, and the spool platform will thus have to rise half a centimeter or so above the floor so the spool is not obstructed.
 
Remember from earlier that an 80mm circular fan has just over 5026mm² of area through which to push or pull air. We want an equal amount of ventilation between the two chambers, so all this air can flow naturally. The ventilation is provided as a series of concentric arcs on the heater's side of the hotbox, symmetric across the y axis. Air will thus hopefully flow in, circulate in the cool chamber, go up into the heating area, and finally distribute the heat and remove any moisture. I thought about trying to collect this moisture, condense it, and just weigh that (as opposed to the spool), but such an approach seemed in the end far more complex and less reliable than a spool measurement. I need to smoketest the airflow, but at worst, it seems that the AC adapter might not get any cooling. I doubt it really needs any. The grommet ought prevent much air from escaping out the AC wire hole.
 
Placement of the heating element posed an interesting problem. Spool rotation solves the problem of even heating along the circumference, but what about the radius? Placing the heater in the center is in any case a non-starter due to the structure of the central column, but it would furthermore result in very uneven heating, with most of the heat being applied to the inner loops of filament. Instead, let's solve for the center of mass of an annular sector of the spool; ignoring air effects and the possibility of partially-consumed spools, this ought be the optimal place to center the heater. Using a quick bit of calculus, we establish the centroid of an annular sector of a disk having internal radius r₁ and external radius r₂ subtending θ to be (4sin(θ/2)(r₂³-r₁³))/(3θ(r₂²-r₁²)) along the radius. Whether this calculation has any real-world merit or is simply false assurance dressed up in math is left as an exercise for the reader.
 
It doesn't seem possible to evenly heat the spool across its width (height in our orientation) unless the heater was stood up along the outside, which would make heating very uneven across the (larger and thus more significant) radius. We can get symmetric heating along this axis three ways: continuous rotation along this axis (necessitating a spherical hotbox), regular flipping of the spool (a special case of rotation, and difficult to do automatically), or placing heaters both on the floor and roof of the hotbox. If this ends up being a big problem, I'll add a ceiling heater. I consider this the main theoretical shortcoming of the dryer, though I'm not yet sure whether it'll matter in practice.
 
We cut the corners out of the top, both to save on material, and because it looks kinda cool imho.
 
[[File:Hotbox.png|the hotbox]]
 
===Small parts/top/platform===
[[File:Lowercoupling.png|thumb|central column elements. clockwise from top: platform, lower coupling, bearing, worm gear, brace, gear]]
[[File:Dryertop.jpg|thumb|top piece]]
 
We still need the central column and the gears. I divided the pieces up so they would print more easily; this is no cost, since we're using screws to join them to the load cell already.
 
The worm gear goes on the rotor of the motor. It must be tangent to some point on the main gear. The platform, gear, and finally bearing are all connected, and the bearing then rests in the coupling, where it can freely rotate. The coupling is screwed using 2 M4x12s into the brace, which is screwed into the top of the load cell (the brace lifts the coupling above the cell's glue). It's easiest to push the platform through the central shaft of the hotbox, mount the gear onto it, and mount the bearing onto the gear.
 
We could print the platform and main gear as a single piece without supports, but our gear could then only be as wide as the central hole in the hotbox. By decoupling them, and inserting only the platform shaft through the hole, the gear can be as large as we want. This gives us a lot more flexibility in placement of the motor mount (a larger gear allows us to place the motor mount further away from the center), which we need in order to accommodate the large load cell.
 
The top is a simple cylinder with a backing plate which fits snugly into the hotbox. I should probably add some kind of latching mechanism. What would be truly ideal is feedback to the MCU regarding whether the top is present, so it could make decisions based on its state. It was printed using [https://us.store.bambulab.com/products/pc-filament?variant=40741214617736 Bambu Clear Black] polycarbonate on smooth PEI. [https://getyarn.io/yarn-clip/30a32c8b-2bd9-44cc-9295-30b756065457 Quoth the raven, "what a shine!"]
 
==Assembly==
Alright, let's print this sumbitch! I printed the cool chamber on textured PEI, and everything else on smooth PEI. Everything was printed on my Bambu X1C using the 0.20mm Standard preset with infill combination, 8% sparse infill density, cross hatch sparse infill pattern, and the Arachne wall generator, except the gears and platform, which were printed using 0.16mm High-Quality plus 50% sparse infill with gyroid.
 
===Hotbox===
I printed the previous iteration of the hotbox using Bambu PAHT-CF, but ran out of it, and thus this final version is AF Nuclear Nylon on smooth PEI. Mount the RC522 to its four mounting stands, and through them to the underside of the hotbox. Install the ceramic heating element and the thermocouple, leaving wires and terminals hanging out of the bottom. Install the fan on the outside, facing out. We thread four M5x45 bolts through the corners in preparation for mating to the cool chamber. We solder one wire from the heater to the thermocouple (neither of these are oriented, so pick either wire, and solder it to the nearer terminal). Pretty easy!
 
[[File:Hotbox-printed.jpg|printed hotbox, bambu paht-cf on smooth pei]]
 
===Cool chamber===
This final cool chamber was printed on textured PEI using Bambu PAHT-CF, which ran out about two thirds of the way through. I finished with AF Nuclear Nylon. The Bambu X1C handled the switch like a boss—it really is a fine machine.
 
We're using the I<sup>2</sup>C mode of the BME680 and RC522, mostly because that's half as many wires I need to solder. We'd need to use SPI if there was an address conflict, or we needed high throughput. With I<sup>2</sup>C we get lower latency and more reliability. The NAU7802 offers only I<sup>2</sup>C.
 
This final cool chamber was printed on textured PEI using Bambu PAHT-CF, which ran out about two thirds of the way through. I finished with AF Nuclear Nylon. The Bambu X1C handled the switch like a boss—it really is a fine machine.
 
[[File:Croom-printed.jpg|cool chamber mid-assembly]]
 
Mount the AC adapter. Insert the grommet into the AC cord hole.
 
Solder things up before trying to install the perfboard. Use long wires for the RC522, which we will mount to the ceiling, and the LM35, which will go up through the center column. The motor controller, BME680, and NAU7802 all go on the perfboard, as do the two Molex connectors. Prepare two long cables with ring terminals, and solder them to the perfboard to provide a 12V bus. The 12V needs go to the power pin on both Molex connectors, plus the motor controller's VM input. The ground needs hit our existing ground bus, which ought be extended to the two Molex connectors' ground pins. Connect both tach pins to the 3.3V bus with 10KΩ resistors. Take a 3.3KΩ resistor out from each, and drop wires to the MCU's tach pins. Attach 0.1nF capacitors to both resistors, and thereby link them to ground (this circuit is explained on my [[PC Fans]] page).
 
I<sup>2</sup>C pins are input/output open-drain lines with pullups. There is a single SDA (data) bus, to which all three I<sup>2</sup>C slaves are connected, and likewise a single SCL (clock) bus.
 
[[File:Assembled-coupling.jpg|thumb|right|assembled load cell + coupling]]
 
{|class="wikitable sortable" border="1" style="float:left; margin: 0 1em 0 0"
|+ MCU pin map
| colspan=2 style="text-align: center;" | J1 || colspan=2 style="text-align: center;" | J3
|-
! Pin !! Target !! Pin !! Target
|-
| 4 || Lower fan PWM (output) || 1 ||
|-
| 5 || Upper fan PWM (output) || 2 ||
|-
| 6 || Upper fan tach (input+ISR) || 42 ||
|-
| 7 || Lower fan tach (input+ISR) || 41 ||
|-
| 15 || || 40 || RC522 interrupt (input+ISR)
|-
| 16 || || 39 || Motor control 1 (output)
|-
| 17 || I<sup>2</sup>C SCL || 38 ||
|-
| 18 || I<sup>2</sup>C SDA || 37 ||
|-
| 8 || LM35 analog data (input) || 36 ||
|-
| 3 || || 35 ||
|-
| 46 || || 0 ||
|-
| 9 || Motor standby (output) || 45 ||
|-
| 10 || || 48 || Motor control 2 (output)
|-
| 11 || || 47 ||
|-
| 12 || Motor PWM (output) || 21 ||
|-
| 13 || Triac (output) || 20 ||
|-
| 14 || || 19 ||
|-
|}
 
Prepare two wires, and solder them to the motor's terminals. Solder the other ends to the motor controller's VM out and ground. Mount the perfboard. Solder the USB-C pigtails (red and black wires; do not use the white and green) to the buck converter output and dial it to 5V. Prepare two wires with ring terminals, and solder them to the input. Mount the buck converter. Connect the USB-C male end to the MCU. Connect all four ring terminals to the output (DC) side of the AC adapter.
 
Smoke one if you've got one.
 
Cut the female end off a decent three-pronged AC cable. Strip it, revealing three wires. The black is live, the white is neutral, and the green is ground. Strip each. Put a 5A fuse inline on the live wire. Bring the three wires through the AC adapter hole. Connect the black and white cables to the 2-port side of a 2-to-4 XHF connector. Prepare four AWG 16 cables. Plug them into the 4-port side of the XHF connector. Add ring terminals to two of them, and the ground wire. I recommend then reinsulating the three terminated wires in a single sheath, and applying heat shrink. Connect the three terminated wires to the input (AC) side of the AC adapter.
 
[[File:Dryercomplete.jpg|thumb|assembled dryer]]
 
The back of the triac has a mounting hole. Looking at the front of the triac, the pins from left to right are Terminal 1, Terminal 2, and Gate. ''Note that the metal surrounding the mounting hole is connected to Terminal 2, and thus possibly live and a shock hazard.'' The triac is bidirectional across the two terminals, and controlled by the gate pin. We can control the gate with our 3.3V, and it takes only 10mA to keep it open, so we wire it directly to a GPIO. The two terminals complete the AC circuit with the heater.
 
Place the motor atop the motor mount, and push it forward so its rotor comes through the central hole. Use six M2 screws to mount the motor face. Push the worm gear onto the exposed rotor.
 
Assemble the load cell coupling and mount it to the central riser.
 
Mount a fan to the outside of the hotbox, facing into the chamber. Mount it with four bolts.
 
Insert the platform through the central hole of the hotbox, with the wide side in the hotbox, and the thin side emerging from the bottom. Mate it to the gear. Mate the gear to the bearing. Place the hotbox atop the cool chamber, so that the bearing fits into the coupling. The gear ought be touching the worm gear along a tangent. Join the chambers tightly with four M5x45 bolts.
 
Plug the AC cable into a live outlet. The MCU ought power on and connect to your WiFi and MQTT broker. It will be serving HTTP, and announcing itself on mDNS. It ought be consuming less than 10 watts so long as you're not actively drying (though the fans will be turned on if the cool chamber gets warm enough).
 
==Firmware==
The firmware is built using [https://github.com/espressif/esp-idf ESP-IDF] in conjunction with CMake (in which it is naturally expressed), using Espressif's newest 5.4 release. I tried to minimize libraries outside of ESP-IDF itself (i.e. no WiFi etc.), coupling my code tightly to "native" ESP-IDF. I avoided [[Arduino]] SDK contrivances (i.e. <tt>pinMode()</tt> etc.) entirely; I believe these do more harm than good.
 
To use it, you'll need prepare a file <tt>esp32-s3/dankdryer/dryer-config.h</tt> using <tt>dryer-network-sample.h</tt> as a template. Configure your ESSID, passphrase, and MQTT broker.
 
All my code is in a single file: [https://github.com/dankamongmen/dankdryer/blob/master/esp32-s3/main/dankdryer.c dankdryer.c]
 
===Initialization===
* The single RGB LED built into the ESP32-S3 is used to indicate initialization errors (or lack thereof). Of course, this LED isn't normally visible from the outside, so it's only useful for testing. Following successful initialization, we turn it off to conserve power and LED lifetime.
* We use the NVS (non-volatile storage) subsystem for persistent storage. We keep a boot count, which is updated immediately following NVS initialization (including formatting if necessary). No errors here are considered fatal. Anything we take as configuration is persisted; any value which isn't present, or can't be read, is replaced by a default built into the code:
** Target temperature
** Exhaust fan PWM
** Intake fan PWM
** Load cell scaling parameter (determined during calibration)
* We enable the ESP32-S3's onboard thermostat.
* We set up two pins for fan 25KHz PWM (output), and two pins for fan tach (input).
** We install a hardware interrupt to count tachometer pulses.
* We initialize an I<sup>2</sup>C master bus and device.
** We probe I<sup>2</sup>C for the RC522, NAU7802, and BME680.
** We install a hardware interrupt for RC522 notifications
* We initialize the NAU7802, and configure the scaling parameter if available.
* We create an event loop, and set up WiFi with a configured ESSID and passphrase.
** We subscribe our WiFi event handler and IP event handler to all relevant events.
** Upon WiFi connection, we attempt to pull a DHCP lease.
** Upon configuration of an IP address, we attempt to connect to the configured MQTT server.
** Upon a failure at any level, we attempt to restart that level.
** If this was being built for mass production, we'd need a way to configure the network outside of code! This would probably take the form of a small display plus a physical button or two, or more likely BLE. We'd also need provide some kind of calibration interface for the load cell (the scaling parameter is specific to the cell instance). But we're not, so we don't.
 
===Main loop===
* Get current time with second resolution using RTC or wrap-corrected TSC.
* Is there an active drying end time? If not, check RC522 for RFID presence. If present:
** Attempt to read and decode RFID.
** Load optimal parameters if we know this filament type.
* Get all three temperatures.
* Are we after the active drying end time? If so:
** Ensure heater and motor are off.
** Otherwise, ensure motor is on. Is the hotbox temp below the target temp? If so:
*** Ensure heater is on. Otherwise, ensure heater is off.
* Get humidity, pressure, and VOC count from BME680.
* Request the average of five consecutive measurements from NAU7802.
* Calculate fan RPMs using tach pulse count and time delta.
* Report all measurements, configuration elements, and drying end time via MQTT.
 
One annoying thing here, as you might have picked up on while reading the pseudocode, is that immediately following the end of a drying operation, we're going to reread the RFID of the spool we just dried, and preload its optimal drying parameters. We don't kick off a dry based on RFID read, but it's still not quite what we want.
 
===Dry request===
A dry request is indicated by specifying a number of seconds to dry. This is converted into a realtime, which becomes the active drying end time. This requires taking a lock. We allow the main loop to take care of the rest, so that setting the expiry time is the only need for mutual exclusion. An ongoing dry can be cancelled by making a request for zero second in the future (this is not a special case, but rather falls naturally out of the main loop's behavior).
 
==Reducing the BOM==
* The Geartisan motor ran $15 off Amazon. Pretty much any other brushed DC motor would cut costs substantially.
* The motor controller can probably be replaced with a power MOSFET plus a flyback diode.
* We could get away with a much cheaper AC adapter.
* Using SMT components together with a custom PCB would cut electronics costs (for instance, rather than a discrete 12V->5V buck converter, we'd just roll our own directly on the PCB), and also lead to a much cleaner interior and fewer assembly failures.
* The Noctua fans are premium; we don't even run the fans very hard, and could maintain silent operation with cheaper ones.
 
Getting into the realm of diminishing returns, the XHF connector runs less than a dollar, but could still be replaced with soldered splicing (effectively free) or a solderfree heat connector (cents).
 
Replacing the buck converter with voltage dividers would waste significant power (generating heat in the process), so I don't like that idea.
 
==Conclusions and lessons learned==
[[File:Pouroneout.jpg|thumb|pour one out for the homies]]
* Don't use the Arduino high-level libraries unless you need the portability.
** I ought have used [https://github.com/espressif/esp-idf esp-idf] from the beginning, and eventually moved to it.
* I should have done my models so that I could test small parts more easily. Look at all the design iterations which didn't make it here to be with us today.
** For instance, all the mounts ought have been their own printings. That way I could check their geometries against the electronics without needing respin the entire chamber. Since I'm already screwing the electronics into the mounts, it's no extra hit to screw the mounts into the chamber.
* <b>Read the datasheets.</b> If it doesn't have a datasheet, don't buy it!
* Always do a PCB (this will be a future blog post).
* My value to a terrorist organization increases with every project.
* Nothing is simple, but everything is easy.
 
===Render===
Should you ever need correct your own high opinion of your intelligence, I've found [https://www.blender.org/ blender] to be a perfect cure. It terrifies me every time I open it. After an hour or two of fucking around with cameras and light sources, I managed to generate this sexy render (on the right) from my unified STLs (on the left):
 
[[File:Render.png|complete dryer, side view]]
 
'''previously: "[[Questions_cheerfully_answered|questions cheerfully answered]]" 2024-07-02'''
 
[[CATEGORY: Projects]]
[[CATEGORY: Hardware]]
[[Category:Blog]]

Latest revision as of 10:56, 30 June 2025

rien n'est simple, mais tout est facile

your humble wikist 2025-06-29

this is the wiki of nick black (aka dank), located at 33°46′44.4"N, 84°23'2.4"W (33.779, 85.384) in the heart of midtown atlanta. dankwiki's rollin' wit' you, though i make no guarantees of its correctness, nor its relevance, nor its timeliness. track changes using the recent changes page. i've revived DANKBLOG, this wiki and grad school having not satisfied ye olde furor scribendi.

hack the planet! don't mistake my kindness for weakness.

i primarily write to force my own understanding, and remember things (a few entries are actually semi-authoritative). i'm just a disreputable Mariner on your way to the Wedding. if you derive use from this wiki, consider yourself lucky, and please get confirmation before relying on my writeups to perform surgery, design spacecraft, determine whether a graph G is an Aanderaa–Rosenberg scorpion, or feed your pet rhinoceros. do not proceed if allergic to linux, postmodern literature, nuclear physics, or cartoonish supervillainy. ■

projects?

Nothing that's any good works by itself, just to please you; you've got to make the Damned Thing work.

unix

i like to stay up late on the computer, looking for answers.

did autistic people design this software? BECAUSE I'M STARTING TO LOVE IT. ■

remarks regarding computers &c

networking

QEMFD! (wikipedia, wolfram) also provides...

still have any questions?

quod erat motherfucking demonstrandum!


"I have never known a greater monster nor miracle than myself." — Michel de Montaigne