wemakethings2023-03-21T18:29:17+02:00https://wemakethings.netMSI Radeon R9 380X green screen of death, and how to "fix" it (maybe)veox2018-08-17T00:00:00+03:00https://wemakethings.net/2018/08/17/msi_radeon_r9_380x_green_screen_of_death<h2 id="ado">Ado</h2>
<p>Purchased this card last year, as part of a long-overdue workstation
upgrade. By then a two-year-old model, it has become sufficiently
uneconomical to krypto grinders to drop into my price bracket.</p>
<p>Somewhat ironically, the heaviest loads it’s seen from me was same old
mining (hey, someone’s got to work those testnets…). Wisened by <a href="/2013/10/12/miner_in_a_fridge_and_radeon_5850_disassembly/">past
experience</a>, I gave it regular (monthly) compressed air
cleaning.</p>
<p>Eventually, though, the system started experiening crashes/lock-ups,
becoming completely unresponsive to inputs - NumLock toggling, <code class="highlighter-rouge">ping</code>s,
anything. An identifying feature of these was the main (HDMI) screen
turning a deep green color, the secondary (DVI) screen going blank (if
my memory doesn’t fail me), and the GPU fans switching to 100%.</p>
<p>I took online to find the cause, but only found people (mostly gamers
of graphics-heavy shooters or simulations) having the same problem on
the same model - not necessarily the same manufacturer, - as well as a
few same-generation AMD-based consumer-grade models; and, after much
fiddling with drivers, OSes, distributions, and mystic incantations,
returning them for a refund.</p>
<h2 id="looks-like-overheating-to-me">Looks like overheating to me</h2>
<p>By then, I was already running <a href="https://prometheus.io/">Prometheus</a> and its <a href="https://github.com/prometheus/node_exporter">Node
Exporter</a> to collect system metrics, albeit
the collector was on the same machine.</p>
<p>Without load, the card was showing around 69 °C. Under load, it would
climb towards 85 °C or so, never quite reaching it prior to a crash.</p>
<p>Once, due to some fluke of luck, the system managed to log 700 °C on
the GPU thermal sensor. The number itself, of course, is bogus: what
amazes me is that Node Exporter managed to read a garbage value from
the sensor, that got collected by Prometheus, then written to RAM cache
of the time-series database, and flushed to disk!.. (Actually, plural -
disks, a software-managed RAID array…)</p>
<p>Anyway, that corroborated my suspicion that thermal paste on the GPU has
dried out. I decided to void my warranty, so that the Internet could get
this settled.</p>
<h2 id="disassembly">Disassembly</h2>
<p>Since I was so sure of my conclusion, I didn’t take many pictures.</p>
<p>(If you’re repeating this process: start with the screws on the
back/board side. On my model, the front mostly covers the fan assembly,
so unless you’re changing the fan, there’s no need to go there.)</p>
<p>Here it is with about a month’s worth of dust accumulation on the
radiator fins, and nine months worth on the “inside”:</p>
<p><img src="/assets/images/2018-06-15-r9_380x_opened.jpg" alt="MSI Radeon R9 380X cracked open" /></p>
<p>The thermal paste was caked, and didn’t take much force to remove with
a plastic spatula. (If you’re having trouble separating the two parts,
do check if you missed a screw first!)</p>
<p>Below, see discoloration (blackening) of the compound used to secure
the ASIC to the board - a tell-tale sign of overheating:</p>
<p><img src="/assets/images/2018-06-15-r9_380x_chip.jpg" alt="MSI Radeon R9 380X chip glue discoloration" /></p>
<p>I applied new thermal paste, and put the thing back together.</p>
<p>After that, the machine shows around 60 °C under no-load conditions,
about 66 °C playing simple puzzle games, and 72 °C grinding on the
Ropsten test network.</p>
<h2 id="whats-the-take-back-here">What’s the take-back here?</h2>
<p>Seemingly, my card had pretty mediocre thermal paste. If you’re
experiencing the “green screen of death”, yours might, too. Unless
you’re willing to void your warranty, take it to a service center.</p>
<p>What also amazed me was that the card <em>did</em> work under no-load
conditions, even with the paste dry. My only guess for the reason is
that the heatsink assembly is pushed <em>against</em> the chip by spring-loaded
screws, so there’s always <em>some</em> contact between the two, even if not
ideal in terms of heat transfer.</p>
<p>Either that, or the fact that I have the computer case mounted
upside-down on the wall, and <em>gravity</em> is somehow involved (as it most
often does).</p>
<p>“Try rotating your computer” doesn’t sound like sane advice, though.</p>
Claiming LivePeer tokens without importing the key into MetaMask (and, perhaps, semi-offline)veox2018-07-19T00:00:00+03:00https://wemakethings.net/2018/07/19/claiming-livepeer-tokens<p>(Note: this started out as a <a href="https://old.reddit.com/r/ethereum/comments/905ywj/claiming_livepeer_tokens_without_importing_the/">Reddit post</a>, but I need a
backup - so here it is.)</p>
<p>LivePeer is using a <a href="https://forum.livepeer.org/t/introducing-the-merklemine/204">“Merkle air drop”</a> for their tokens, a
concept I’ve first seen described by Richard Moore <a href="https://blog.ricmoo.com/merkle-air-drops-e6406945584d">in an article about 4
months ago</a>.</p>
<p>It’s an interesting one, since the mechanism is op-in, preventing some
spam. (LivePeer’s particular distribution rules <em>will</em> eventually result
in spam, when the “slow start” period ends; but that’s IMO and OT.)</p>
<p>To receive their tokens, one:</p>
<ul>
<li>goes to an IPFS-hosted page;</li>
<li>downloads the 100-megabyte “list” (actually a merkle tree) of eligible
accounts;</li>
<li>looks themselves up in the “list”;</li>
<li>submits a proof of being in the “list” to an on-chain contract.</li>
</ul>
<p>This is rather streamlined when using MetaMask and a fast connection.</p>
<p>But what if one of the two is unavailable at the point where the private key resides?</p>
<h2 id="checking-eligibility--generating-the-proof">Checking eligibility / generating the proof</h2>
<p>Go to the proof generation page (replace the account address with yours):</p>
<p><a href="http://gateway.ipfs.io/ipfs/QmUvAFQZxbgMCqCMLUSj2kQBpZUhj5qi8KhmPDVvv9apfj?address=0x04b3fAAA7c8127A80eB6D24672CfdAF4AeCABbF8">http://gateway.ipfs.io/ipfs/QmUvAFQZxbgMCqCMLUSj2kQBpZUhj5qi8KhmPDVvv9apfj?address=…</a></p>
<p>Or, if you have a local IPFS node (perhaps with an IPFS Companion plugin):</p>
<p><a href="http://127.0.0.1:8080/ipfs/QmUvAFQZxbgMCqCMLUSj2kQBpZUhj5qi8KhmPDVvv9apfj?address=0x04b3fAAA7c8127A80eB6D24672CfdAF4AeCABbF8">http://127.0.0.1:8080/ipfs/QmUvAFQZxbgMCqCMLUSj2kQBpZUhj5qi8KhmPDVvv9apfj?address=…</a></p>
<p>(Note that you can’t edit the on-page “Input Data URL” without fiddling
with the page source.)</p>
<p>Click “Load” to generate the merkle proof. It will be of the form:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>0x6165d6cf7369700441b712144d8a84c953dcbe9920b088f970eb502b2f6f19166d721de3c88e901947bc24e1eadd1e6ca0330effaaae234eed46b986487aff49e14b9bfb3e913b61dc728d1b9723e2878bda2696f52df657c02f8f70a07e5b308b55289da0998744c56c9fc120819770f6f677eb896b35c46643749ea3a0ac56320a0d77462ffa8f65e00e4060ad46fdf4aaf8c0b3f889070b392916a9e57a11f83b842b1e22bb3fe0581140f1654ec33c29561da539fad6c0279cd9a3449eb0a582c0d5dd24f64ad0c0a00aa3e4b96d00a785b9b96b75b1f11012a75439f3036a8661a4743e25e01b4ecde186e081416a4b18e0ce671f46743ab8b919433ba36ad2fa4331c9ebbfc19b4454115240531aa6d6452c7f4b98ce89bcc0c0092dfe11580dc8fbcb38f8e6aa79ecc6b66cf8cf3d1705fd141c107681d1025532c9d5e5a1d50a2303f03e37593fe8ae6dc3d66097300d2f7a68e589c330b67a46a61936a4b0d7b0b35da7cc711fd2a3da189c9a1ef3dc07789e2675fc995cb07cf786d6300b12f87dc96cfd5c35a78b610f9ab9d23e512bbd2550e830899460a91c83eb65a228eb7a0b00238ebaf97019fb6968046b5f76547c90e578cb055a00633981f5ac1301ba36888811291fb57e2c34d2abe5d126f68cf5ea3e44133ade8a7721f2672c9930573127cc98dd63e59a49aabb846169543380ca4665a7f47dd96fd46f6243507e7da5820a26522e3ce2223234413087f9d83baedf0c244e356f5933ce5432faf5ec0e784e42c9f49ec57c0843998953de393caabfd906c9f78c8a878396323c59b1f49c7635610d774782e7e18a0feb43093b7a70f7ad98340accccb9167971b92fe9762830d3f20908fb10fafa9929adfde2f65a4e90327ebc1f7460f55592404a5bd804dd4060fbbaf11a6bdc0557c70c812ec5cd9aa8007ed51e74a86b2f0aceaa39987ce1ee5e1150dc99db6336cca1bf9a005c776d0e3fc3
</code></pre>
</div>
<h2 id="stitching-together-transaction-data">Stitching together transaction data</h2>
<p>To claim the token, a transaction must be sent to the
<a href="https://etherscan.io/address/0x8e306b005773bee6ba6a6e8972bc79d766cc15c8#code">MerkleMine contract</a>.</p>
<p>I’ve previously used a MetaMask account to generate <a href="https://etherscan.io/tx/0xc96a4f715d12e2f387582c9d1d6f6d730f5819e0c11aa4856282b25c76587f84">a sample transaction</a>:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>Function: generate(address _recipient, bytes _merkleProof) ***
MethodID: 0x2c84bfa6
[0]: 000000000000000000000000f75b78571f6563e8acf1899f682fb10a9248cce8 <-- claiming account address
[1]: 0000000000000000000000000000000000000000000000000000000000000040 <-- proof data[] location pointer
[2]: 0000000000000000000000000000000000000000000000000000000000000280 <-- data length
[3]: ... <-- start of data
</code></pre>
</div>
<p><code class="highlighter-rouge">[0]</code> is self-explanatory; <code class="highlighter-rouge">[1]</code> will always be a pointer to the same
location - <code class="highlighter-rouge">0x40</code>, where the proof data length <code class="highlighter-rouge">[2]</code> is; <code class="highlighter-rouge">[3]</code> and all
the way to the end is the actual proof data (<code class="highlighter-rouge">0x6165d6cf...</code> from the
previous step).</p>
<p>The item in position <code class="highlighter-rouge">[2]</code> will likely require editing, as the length of
proof data depends on the location of a node in the merkle tree.</p>
<p>With the <code class="highlighter-rouge">0x</code> prefix, the proof data string is 1410 characters; so -
1408 without the prefix. Each character represents a nibble (half a
byte), so that’s 704 bytes. <code class="highlighter-rouge">704</code> decimal is <code class="highlighter-rouge">0x2c0</code> hexadecimal.</p>
<p>A Python console helper:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="o">>>></span> <span class="n">proof</span> <span class="o">=</span> <span class="s">'0x6165d6cf...'</span>
<span class="o">>>></span> <span class="n">l</span> <span class="o">=</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">proof</span><span class="p">)</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span>
<span class="o">>>></span> <span class="n">datalen</span> <span class="o">=</span> <span class="nb">hex</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">l</span><span class="p">))</span>
<span class="o">>>></span> <span class="k">print</span><span class="p">(</span><span class="n">datalen</span><span class="p">)</span>
<span class="mh">0x2c0</span></code></pre></figure>
<p>For my non-MetaMask account, the transaction data <a href="https://etherscan.io/tx/0xc736345ef0acfbf93ac3c7461113de095ee44d846ad41ba7480c08d715aa306e">will look
like</a>:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>Function: generate(address _recipient, bytes _merkleProof) ***
MethodID: 0x2c84bfa6
[0]: 00000000000000000000000004b3faaa7c8127a80eb6d24672cfdaf4aecabbf8 <-- claiming account address
[1]: 0000000000000000000000000000000000000000000000000000000000000040 <-- proof data[] location pointer
[2]: 00000000000000000000000000000000000000000000000000000000000002c0 <-- data length
[3]: 6165d6cf7369700441b712144d8a84c953dcbe9920b088f970eb502b2f6f1916 <-- start of data
[4]: ...
[24]: 1e74a86b2f0aceaa39987ce1ee5e1150dc99db6336cca1bf9a005c776d0e3fc3 <-- end of data
</code></pre>
</div>
<p>I didn’t bother writing code to generate the transaction data
to-be-submitted, but stitched it together in a text editor. It’s of the
form:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>0x2c84bfa600000000000000000000000004b3faaa7c8127a80eb6d24672cfdaf4aecabbf8000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c06165d6cf7369700441b712144d8a84c953dcbe9920b088f970eb502b2f6f19166d721de3c88e901947bc24e1eadd1e6ca0330effaaae234eed46b986487aff49e14b9bfb3e913b61dc728d1b9723e2878bda2696f52df657c02f8f70a07e5b308b55289da0998744c56c9fc120819770f6f677eb896b35c46643749ea3a0ac56320a0d77462ffa8f65e00e4060ad46fdf4aaf8c0b3f889070b392916a9e57a11f83b842b1e22bb3fe0581140f1654ec33c29561da539fad6c0279cd9a3449eb0a582c0d5dd24f64ad0c0a00aa3e4b96d00a785b9b96b75b1f11012a75439f3036a8661a4743e25e01b4ecde186e081416a4b18e0ce671f46743ab8b919433ba36ad2fa4331c9ebbfc19b4454115240531aa6d6452c7f4b98ce89bcc0c0092dfe11580dc8fbcb38f8e6aa79ecc6b66cf8cf3d1705fd141c107681d1025532c9d5e5a1d50a2303f03e37593fe8ae6dc3d66097300d2f7a68e589c330b67a46a61936a4b0d7b0b35da7cc711fd2a3da189c9a1ef3dc07789e2675fc995cb07cf786d6300b12f87dc96cfd5c35a78b610f9ab9d23e512bbd2550e830899460a91c83eb65a228eb7a0b00238ebaf97019fb6968046b5f76547c90e578cb055a00633981f5ac1301ba36888811291fb57e2c34d2abe5d126f68cf5ea3e44133ade8a7721f2672c9930573127cc98dd63e59a49aabb846169543380ca4665a7f47dd96fd46f6243507e7da5820a26522e3ce2223234413087f9d83baedf0c244e356f5933ce5432faf5ec0e784e42c9f49ec57c0843998953de393caabfd906c9f78c8a878396323c59b1f49c7635610d774782e7e18a0feb43093b7a70f7ad98340accccb9167971b92fe9762830d3f20908fb10fafa9929adfde2f65a4e90327ebc1f7460f55592404a5bd804dd4060fbbaf11a6bdc0557c70c812ec5cd9aa8007ed51e74a86b2f0aceaa39987ce1ee5e1150dc99db6336cca1bf9a005c776d0e3fc3
</code></pre>
</div>
<h2 id="assemblingsigningsubmitting-the-transaction">Assembling/signing/submitting the transaction</h2>
<p>This depends on the software used - MEW/MyCrypto in offline mode, <code class="highlighter-rouge">geth</code>
console, <code class="highlighter-rouge">parity</code>+<code class="highlighter-rouge">ethers.js</code>, <code class="highlighter-rouge">web3.py</code>+Infura… In general, the
transaction will have:</p>
<ul>
<li><code class="highlighter-rouge">from</code>: the claiming account’s address;</li>
<li><code class="highlighter-rouge">to</code>: <code class="highlighter-rouge">0x8e306b005773bee6bA6A6e8972Bc79D766cC15c8</code>;</li>
<li><code class="highlighter-rouge">data</code>: the “stitched together” data above (starting with <code class="highlighter-rouge">0x2c84bfa6</code>);</li>
<li><code class="highlighter-rouge">gas</code>: 200000 was enough in both cases for me - might work for you,
too, if your proof’s length is around the same 700 bytes;</li>
<li><code class="highlighter-rouge">gas_price</code>: the usual: tricky (read below);</li>
<li><code class="highlighter-rouge">nonce</code>: the usual: the next number after the last transaction’s
<code class="highlighter-rouge">nonce</code> for a given account.</li>
</ul>
<p>The transaction is not currently time-critical, so anything that has a
chance of getting confirmed within 3 hours would be an “OK” gas price.
Check out <a href="https://ethgasstation.info/txPoolReport.php">EthGasStation’s recently-improved transaction pool report
page</a>, or use its general front-page estimate.</p>
ENS components, the bidding process, and "stale" bidsveox2017-06-19T00:00:00+03:00https://wemakethings.net/2017/06/19/ens-intro<p><em>(This article has been extracted from an upcoming one, as it is somewhat
off-topic to the issue discussed there, and overly verbose at that.)</em></p>
<p>Grossly over-simplified, the <a href="https://ens.domains/">Ethereum Name Service</a> is a set of
contracts that allow looking up an Ethereum address when given a “name”.</p>
<p><strong>For a human</strong>, an address is hard to memorise, but a name is not. <strong>For a machine</strong>,
names are unwieldy, since they vary in length, and are non-homogenous as a set
in many other ways.</p>
<h2 id="specifications-and-clients">Specification(s) and clients</h2>
<ul>
<li>The <a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-137.md">ERC 137</a> finalised standard, detailing how human-friendly
names (strings) are to be translated to machine-friendly keys (of 32 bytes),
along with other details.</li>
<li>The <a href="https://github.com/ethereum/EIPs/issues/162">EIP 162</a> proposal, describing an approach for name registration.</li>
<li><a href="https://github.com/ethereum/ens-registrar-dapp"><code class="highlighter-rouge">ens-registrar-dapp</code></a>, a browser-based client by the developers
of ENS for name registeration and related tasks.</li>
</ul>
<p>Note that by now, there are many other clients for interacting with ENS.</p>
<p>Some, such as <a href="https://github.com/ethers-io/ethers-ens">ethers-ens</a>, are stand-alone, tailored specifically
for interacting with ENS from the command line.</p>
<p>Others, such as <a href="https://www.myetherwallet.com/">MyEtherWallet</a>, are part of a larger “wallet” software
package, meant for casual use by reasonably well-informed users.</p>
<p>Yet others, such as <a href="https://github.com/cpacia/ens-chrome-extension">ens-chrome-extension</a>, focus on
easy name resolution for next to everybody, without unnecessary details (such
as how to acquire one).</p>
<h2 id="implementation-blocks">Implementation blocks</h2>
<p>A <a href="https://www.youtube.com/watch?v=kjjg_sDcIg8">lightning talk video</a> (11 minutes) is available that explains the below
in a very accessible manner.</p>
<p>The ENS contracts work as a system, with the primary components being:</p>
<ul>
<li>The <strong><a href="https://etherscan.io/address/0x314159265dd8dbb310642f98f50c066173c1259b">Registry</a></strong> (<a href="https://github.com/ethereum/ens/blob/7e377df83f733a4213f123602239fad073bdbaa7/contracts/ENS.lll">source</a>), a data store linking
keys of 32 bytes to an “owner” address, a “resolver” address, and a
“time-to-live” integer value. An entry in this store is called a node.</li>
<li>The <strong><a href="https://etherscan.io/address/0x6090a6e47849629b7245dfa1ca21d94cd15878ef"><code class="highlighter-rouge">.eth</code> Registrar</a></strong> (<a href="https://github.com/ethereum/ens/blob/7e377df83f733a4213f123602239fad073bdbaa7/contracts/HashRegistrarSimplified.sol#L103">source</a>), which
allows claiming ownership of a node by participating in an auction.
The winner of an auction gets the rights to modify the node.</li>
<li>The <strong><a href="https://etherscan.io/address/0x6090a6e47849629b7245dfa1ca21d94cd15878ef">Deed</a></strong> contracts (<a href="https://github.com/ethereum/ens/blob/7e377df83f733a4213f123602239fad073bdbaa7/contracts/HashRegistrarSimplified.sol#L24">source</a>), an utility
to segregate user funds during and after an auction. A Deed hadles one
bid, and can only be interacted with by proxy, through the Registrar
that created it.</li>
<li>A <strong><a href="https://etherscan.io/address/0x1da022710df5002339274aadee8d58218e9d6ab5">Public Resolver</a></strong> (<a href="https://github.com/ethereum/ens/blob/7e377df83f733a4213f123602239fad073bdbaa7/contracts/PublicResolver.sol">source</a>), an
“example” interface for setting and retrieving data <em>about</em>
a node. The data in this particular case is an address that the node
<em>resolves to</em>, and/or a content hash (e.g. A Swarm/IPFS link). Custom
Resolvers are also possible.</li>
<li>The <strong><a href="https://etherscan.io/address/0x9062c0a6dbd6108336bcbe4593a3d1ce05512069"><code class="highlighter-rouge">.reverse</code> Registrar/Resolver</a></strong>
(<a href="https://github.com/ethereum/ens/blob/7e377df83f733a4213f123602239fad073bdbaa7/contracts/ReverseRegistrar.sol">source</a>), which allows owners of an Ethereum account to
link an ENS node to it, and others to look up such links.</li>
</ul>
<p>The system is experimental, and soft-scheduled for an upgrade within
2 years. A <a href="https://github.com/ethereum/ens/blob/7e377df83f733a4213f123602239fad073bdbaa7/contracts/HashRegistrarSimplified.sol#L170">hard limit of 4 years</a> has also been set, at
which point the <code class="highlighter-rouge">.eth</code> Registrar will no longer allow new auctions,
thereby forcing an upgrade if it hasn’t been done by then, or
obsoletion.</p>
<p>See the <a href="http://docs.ens.domains/en/latest/faq.html">FAQ</a> for many more details.</p>
<h2 id="eth-registrar-auction-structure"><code class="highlighter-rouge">.eth</code> Registrar auction structure</h2>
<p>The auction is a “blind” <a href="https://en.wikipedia.org/wiki/Vickrey_auction">Vickrey-style</a> one, divided
into two stages.</p>
<p>During the <strong>“bidding” stage</strong>, participants are expected to submit “sealed”
bids, without knowing what others bid. The latter is achieved by not
sending the bid info in clear text, but hashing it with random data
called “salt” that only the bidder knows, and submitting the result of
that operation.</p>
<p>In effect, the fact that a bid has been placed becomes publicly
known, but the rest does not.</p>
<p>The sealed bid has ether attached to it. It can contain more ether
than the bid, to “conceal” the “actual” bid amount.</p>
<p>During the <strong>“reveal” stage</strong>, previously submitted sealed bids are
made public. That is done by making public the name that the bid
is for, the actual amount, and the salt.</p>
<h2 id="auction-bidding-scenario-almost-normal">Auction bidding scenario (almost normal)</h2>
<h3 id="day-zero">Day zero</h3>
<ul>
<li>Alice is tired of sending her ETH address by encrypted mail every
time she wants to share it. She wants to say it out loud, or write
it on a napkin, and be done with it. She’s <strong>heard of ENS, and that
MyEtherWallet supports it</strong>, but she hasn’t used either before.
She’s downtown, her phone is broken, and she’s got lunch scheduled
in an hour. She decides to try her luck, and <strong>walks into the closest
internet café</strong>.</li>
<li>She goes to MEW’s page, checks to see that <code class="highlighter-rouge">aliceinwonderland.eth</code>
is unavailable, considers <code class="highlighter-rouge">aliceliddell.eth</code> (her full name),
then <code class="highlighter-rouge">analice.eth</code> (“an alice”), <em>curses</em>, and settles on
<code class="highlighter-rouge">cancelot.eth</code> (<strong>nonsense that is easy to pronounce</strong>).</li>
<li>She checks MEW’s <a href="https://myetherwallet.groovehq.com/knowledge_base/categories/ens">self-help center</a> to <strong>see what could go
wrong</strong>.</li>
<li>She <strong>unlocks her wallet using a mnemonic phrase</strong> from her home computer’s
MetaMask wallet, and proceeds to fill in the details.</li>
<li>She shrugs off the fine print, because the display renders
letters thinly. <strong>When asked to take a screenshot of the bid’s info,
she writes it down on a napkin</strong>, and folds it to her pocket. She
confirms the bid.</li>
<li>MEW <strong>sends out two transactions</strong> simultaneously - one <a href="https://etherscan.io/tx/0xd1101fdaf51c25959ce330f391edd8d42b075cfd4db1534db134f5d343cdd052">opening the
auction</a>, another <a href="https://etherscan.io/tx/0x24bae12a18c27e8c3d15c172e8db625f9b9db8477237ba7e14e9badf939c635c">placing a sealed bid</a>. Links are
shown for both.</li>
<li>Alice waits for the transactions to go through. It’s taking
a while, so she checks Reddit to see if there’s a DDoS or something.
<strong>There’s an ICO</strong>.</li>
<li>“How long is forever?”, Alice <em>curses</em>. Her time is up, she <strong>logs out</strong>,
and heads to lunch.</li>
<li>She <strong>tells everyone</strong> there how she’ll soon have this easy-to-remember
Ethereum name, all the while replenishing her supply of napkins.
Mallory seems mildly interested by the description.</li>
<li>Unbeknownst to her, many Ethereum nodes crash in the ICO aftermath,
clearing her transactions from their memory. However, they are
routinely <strong>re-broadcast by a few hardened nodes</strong>, performed as a
public service by their operators to ward off support requesters.</li>
<li>When she gets home, she finds a napkin in her pocket, and puts it
by the computer. She <strong>makes a mental note</strong> to check back when the
bidding phase is over, so she can reveal her bid.</li>
</ul>
<h3 id="day-one">Day one</h3>
<ul>
<li>Next day, Alice <strong>checks if the transactions went through</strong>. They have,
almost 18 hours after being sent.</li>
</ul>
<h3 id="day-two">Day two</h3>
<ul>
<li>Alice gets her phone repaired. She <strong>puts a reminder in a calendar
app</strong>, with the actual time for the reveal phase, once she comes
home and notices the napkin still there by her computer.</li>
</ul>
<h3 id="day-three">Day three</h3>
<ul>
<li>When time comes to reveal, Alice is away from home, so her secret-bearing
napkin isn’t readily available. She gets to it much later, and uses MEW again,
since she <strong>doesn’t feel like experimenting</strong> with MetaMask.</li>
<li>She can’t copy-paste from her napkin, so <strong>uses the “manual input”
boxes</strong> instead. The <a href="https://etherscan.io/tx/0x6f9b81008313acdeef21f76904f4b8f4a3d835ca10509253d8f3c2999e6793fb">first transaction</a> fails, since she
<strong>gets the amount wrong</strong> - 0.0042 ETH instead of 0.042 ETH.</li>
<li>She tries again, <strong>triple-checking all the input boxes</strong>, and submits
her <a href="https://etherscan.io/tx/0x8df0e75a770a7160d790c5d3ce2b5ff1ccd9cb84e47a173cb7aa2299ce9a3679">second transaction</a>.</li>
<li>By coincidence, there’s another crowdsale event starting just about
then. <strong>The second transaction gets “stuck”</strong>. Alice <em>curses</em>.</li>
<li>She wonders how to <strong>change gas price</strong> in MEW, since there didn’t seem
to be an option for that. She looks through the page thoroughly,
and finds it in the footer, on the right, surrounded mostly by
project trivia.</li>
<li>She makes a mental note to <strong>increase gas price for time-critical
transactions</strong>, if she ever has a need to do those.</li>
</ul>
<h3 id="day-four">Day four</h3>
<ul>
<li>The reveal transaction <strong>gets included in a block by next morning</strong>.
Alice feels relieved.</li>
</ul>
<h3 id="day-five">Day five</h3>
<ul>
<li>The reveal phase for <code class="highlighter-rouge">cancelot.eth</code> ends. <strong>Alice was the only bidder</strong>,
or perhaps everyone else failed to reveal their bids.</li>
<li>She follows the instructions to <a href="https://etherscan.io/tx/0x75f04111517a21644d89cbbc4e9e9fac3af1da2d941dea8b9bcac563d8bbf758">finalise the auction</a> in
the <code class="highlighter-rouge">.eth</code> Registrar.</li>
<li>She <a href="https://etherscan.io/tx/0xe6507ba188adb26827b97ff6c9cd565fdb49c3c400d167c41217b2b502a23d9b">sets the resolver</a> in the ENS Registry to the Public
Resolver.</li>
<li>She <a href="https://etherscan.io/tx/0xe50db16ff8b18364e2ec62708f82b8b41020058cb95b7c70f258cd31165cddf1">sets <code class="highlighter-rouge">cancelot.eth</code> to resolve</a> to her wallet address
in the Public Resolver.</li>
<li>She <a href="https://etherscan.io/tx/0x94bba0c3e3022532d7a58b64b403e5441331ba1ec5f08d4c34a93d9062366696">sets the reverse name</a> to <code class="highlighter-rouge">cancelot.eth</code> for her
address in the Reverse Registrar.</li>
</ul>
<h2 id="possible-pitfalls">Possible pitfalls</h2>
<p>There are many things that could have gone wrong for Alice. Most
importantly:</p>
<ul>
<li>She could have lost the “seed phrase” for her bid, or forgotten
the amount that she placed in the sealed bid - e.g., due to <strong>losing
that napkin</strong>, or <strong>bidding “about 4 euros”</strong> (0.013114754098360656 ETH).</li>
<li>She could have failed to reveal her bid during the appropriate phase -
e.g., <strong>due to another unexpected ICO</strong>, or <strong>a “regular” DDoS</strong>, or <strong>getting
in a car crash</strong> with Mallory, or simply <strong>forgetting to do it on a hung-over
weekend</strong>.</li>
<li>She might have lost the keys to her wallet altogether - e.g. by
bidding from a device that got broken later, and <strong>not having a
backup</strong>.</li>
<li>She might have gotten her bidding account compromised - e.g. by
<strong>a keylogger at the café</strong>.</li>
<li>Her <strong>client of choice might have had a bug</strong>, particularly one that
mangles the bid/reveal transaction <code class="highlighter-rouge">data</code>, screws up transaction
nonces, or some similar technicality. So, although she might have
done everything “correctly”, the software she used might’ve not.</li>
</ul>
<p>If you think all of the above are so unlikely that they’d never happen -
think again: most of them are “quotes” from the ENS gitter channel, of
people confused as to what has happened, exactly, and taking the time to
figure it out.</p>
<h2 id="say-alice-fails-to-reveal">Say Alice fails to reveal?</h2>
<p>If she simply couldn’t make it in time, but still had all the necessary
information, she could reveal her bid anyway. <strong>That would be a sensible
thing to do</strong>, since the “conceal” amount would be returned in full. As
to the actual bid amount, she’d get 0.5% of it back.</p>
<p>19 days after a bid has been placed, the bid “expires”, or becomes
“stale” (not official terms). Most probably, that comes 14 days after
the related auction’s end.</p>
<p>After bid expiration, <strong>anyone becomes eligible to 0.5% of the entire
bid amount</strong>. (There’s no way to determine what part of that was the
actual bid - it’s never been revealed). All they need to perform is a
cancellation call, providing a bidder’s address and the unrevealed bid
data.</p>
<h2 id="current-state">Current state</h2>
<p>By now the situation has evolved such that there is a race by multiple
third parties to claim the reward discussed above. This, in turn, results
in unnecessary stress on the network. Even if very small, this stress
can be avoided by re-designing the cancellation mechanism.</p>
<p>(The developers of ENS are aware of all this.)</p>
<p><strong>This is not a bug</strong>. It is more of a logical conclusion to the set
of rules layed out by the <code class="highlighter-rouge">.eth</code> Registrar <a href="https://etherscan.io/address/0x6090a6e47849629b7245dfa1ca21d94cd15878ef">contract</a>.</p>
<h2 id="some-stats">Some stats</h2>
<p>As of block 3898200, the ENS <code class="highlighter-rouge">.eth</code> Registrar is the top account
by gas used in transactions sent to it, according to <a href="http://ethgasstation.info/gasguzzlers.php">ETH Gas
Station</a>. It’s been in that position for the most
of its existence, surpassed only occasionally, briefly, and violently
by a few crowdsales.</p>
<p>It accounts for 26.05% of gas used in the last 10 thousand blocks. The
closest contender is 4.56 times smaller (5.71%), and is the Bittrex
exchange.</p>
<p>The above is to demostrate that users of ENS are not a fringe group,
but in fact a large constituency among those using this blockchain for
computation, at least by this metric.</p>
<p>Over <a href="https://ens.codetract.io/">161 thousand bids have been placed</a> since the launch of
ENS on May 4th. Since the start of June, the number of unrevealed bids
hovers around 15-17 thousand.</p>
<p>As of this writing (June 19th, block 3898364), the number of bids
properly revealed (ever) is 137003, and the number of cancelled ones is
6952. That is 5806.112 ETH in total, of which 29.031 ETH (0.5%) went to
those doing the cancelling. (Source: <a href="https://gitlab.com/veox/cancelot/blob/a9925ba1ef406200a7b44bccc5b3f43bb04a718a/get-stats.py">this script</a>.)</p>
<p>At current trading price of 316 ETH/EUR, that’s respectively
1.834 million and 9.173 thousand euros. Another way to look at it
is <strong>slightly less than the mining revenue for 63 or 6 blocks,
respectively</strong>, in less than 7 weeks.</p>
<p>About 4.83% of bids are not being revealed in time by the people who
placed them. Instead, they are being cancelled by someone else after
becoming “stale”. This means a large loss of funds for the original
bidders, a sizeable reward for <em>some</em> effort to those cleaning up the
mess, and a near-negligible increase in ether valuation for <em>everybody</em>
in the ecosystem, including those who lost and gained.</p>
<p>On the other hand, for most of expired bids, there are at least two
cancellation transactions that make it into the blockchain, and anywhere
up to 20 that get replaced with a higher gas price while still in the
unconfirmed transaction pool.</p>
<p>(More on the latter - later.)</p>
A bedtime story about Gnosis and their Icy-Oveox2017-04-25T00:00:00+03:00https://wemakethings.net/2017/04/25/gnosis_ico<p>This started as a <a href="https://www.reddit.com/r/ethtrader/comments/67fm4f/every_post_is_about_gnosis_what_is_it_eli5_please/dgq0yc2/">reply on reddit</a>:</p>
<blockquote>
<p>Every post is about Gnosis - what is it? ELI5 please</p>
</blockquote>
<p>Here’s a bedtime story. It’s intended to be read to children, until they can’t take it anymore and go to sleep.</p>
<h2 id="knowing-for-sure-knowing-what-will-happen-and-knowing-how-many-people-agree-with-you">Knowing for sure, knowing what will happen, and knowing how many people agree with you</h2>
<p>A lot of people agree that getting a way <em>to know things for sure</em>, or at least to know <em>who’s with you on this one</em>, <em>who agrees with you</em>, is a nice thing indeed. And it’s a <em>very</em> nice thing to <em>know for sure about the future</em>. Getting a glimpse into one of the futures - can you imagine?..</p>
<p>Some people disagree with that and say that knowing is overrated (don’t bother about this word, I’ll explain later, or wiki-wiki). But those that do agree, call it <em>Knowing</em> in general, with a big one up front; or, for one special way of knowing - <em>Gnosis</em>.</p>
<p>Some folk (let’s call them the <em>Gnosis team</em>) came up with this very new special way of knowing, knowing what will happen in the future even. But it only works if anyone can use it, if only they wish to. I mean, if they agree that it’s a nice thing, then they can use it. If they don’t agree, their opinion doesn’t matter to those who do - that’s what “agree” <em>means</em>.</p>
<h2 id="icy-o">Icy-O</h2>
<p>Confused yet? No?.. Well, here comes the good part. :)</p>
<p>The Gnosis team needed some stuff so they could “make” their Gnosis - to <em>know for sure</em> that they could <em>know for sure in the future</em>. (Yes, fractals, exactly!) Like food, beds, fast internet, same things you do. But they needed to <em>know</em> that they’d have this stuff for a long time, like a couple years, maybe more, and they weren’t a small team.</p>
<p>So, they came up with a fair way to get this stuff <em>right now</em>, from people who think they agree right now, or maybe would agree in the future. They called this new way of getting stuff an <em>Icy-O</em>, and they worked very hard for a long time to make sure, to <em>prove</em> it was fair. They wanted to <em>know for sure</em> that it was fair.</p>
<p>Almost everyone agreed that <em>if</em> it was fair, it could be very nice. But not the other way around: if it was nice, that wouldn’t always mean that it was fair - it could be either.</p>
<h2 id="medals-for-everybody">Medals for everybody</h2>
<p>When they heard of this new Icy-O, a lot of people here said that it wasn’t <em>really</em> fair, because it’s not fair <em>to everyone</em> (and you can only be <em>fair</em> when you’re fair to <em>everyone</em> - that’s what fair <em>means</em>). In fact, many said that it wasn’t fair to most, so it wasn’t fair at all. There was even some shouting.</p>
<p>See, many people didn’t care about Gnosis, or its Icy-O, until not that long ago. Maybe before then, the whole thing didn’t seem that important yet, or maybe because they were very busy doing other things.</p>
<p>But the Gnosis team <em>knew for sure</em> by now their Icy-O was fair, or at least they thought so. See, they weren’t using Gnosis for their Icy-O to begin with, since they didn’t have it yet, since they needed the stuff…</p>
<p>(No, the chicken and egg are the same thing.)</p>
<p>… Anyway, the Gnosis team said:</p>
<p>“Here’s the thing we’re going to give to everyone who wants it, and agrees with us that it’s a nice thing. We’ll have it ready in a few years. Here’s how much stuff we’ll need first. It’s not much, and anyone who wants to give some can give as much as they’d like.”</p>
<p>“For all the stuff you give us, we’ll give you a prize, a medal. At the end, we’ll count who gave how much, and the more you gave, the bigger your medal will be. But the earlier you gave, the smaller your medal will be. So, if you gave a little at the beginning, or a lot at the end, your medal would be the same size! We’re happy with you both, and we think this is fair.”</p>
<p>“Oh, and as soon as we get as much stuff as we want, we won’t be taking any more. We’re not greedy.”</p>
<p>“That’s our Icy-O.”</p>
<p>When the time came, the Gnosis team got as much as they wanted in ten minutes, from just a few people who didn’t care about medals in the first place.</p>
<h2 id="some-people-just-dont-like-missing-out">Some people just don’t like missing out</h2>
<p>If you were talking on the phone, or sleeping, or riding a bicycle from work, you could have missed it. In fact, that’s what happened to most people, one way or another. Luckily, those people didn’t know that they were missing out, so they didn’t really miss out at all.</p>
<p>There were some people, though, that <em>did</em> want to give some stuff in the Icy-O, and <em>did</em> want a medal. (Don’t judge.)</p>
<p>Some of them just wanted a little medal of their own, because they like medals.</p>
<p>Some wanted a big medal for being a hero and barely saving the day.</p>
<p>And some wanted there to be an awful lot of medals, so that a lot of people could say they “did their part, gave some stuff”, and show a medal that said they weren’t greedy.</p>
Conditionally cancelling part of a dapp's state changesveox2016-08-08T00:00:00+03:00https://wemakethings.net/2016/08/08/conditional_cancel<h2 id="intro-history----skip-if-in-a-hurry">Intro (history – skip if in a hurry)</h2>
<p>I’ve recently been busy writing a <code class="highlighter-rouge">pygments</code> <a href="https://bitbucket.org/birkenfeld/pygments-main/pull-requests/626/add-solidity-lexer/diff">lexer for Solidity</a>.
This has been an unusual learning process. Instead of getting
familiar with known tropes for a language, I got a view of what’s
possible and how it’s done on a lower level.</p>
<p>For example, here’s a little (as of yet untested) <a href="https://bitbucket.org/veox/pygments-main/src/1dd7c6d0d897d6add39a83fa280930b2620915a8/tests/examplefiles/example.sol?fileviewer=file-view-default#example.sol-119">trick</a>
to keep multiple references to the same object in a mapping. (Relevant:
<a href="http://vessenes.com/solidity-frustrations-references-and-mapping/">post on references and mappings</a> by Peter Vessenes, published
on the same day that example was written.)</p>
<p>Anyway, it also occured to me yesterday that another under-used feature
of the language could allow <strong>conditionally “reversing” undesired state
changes that occured during dapp execution</strong>.</p>
<p>This has implications. Consider a dapp that modifies the state (changes
its own globals, makes <code class="highlighter-rouge">send()</code>s and <code class="highlighter-rouge">call()</code>s), inspects the state
after execution, and resets to a previous state if the results are
unacceptable, - then continues with the rest of its code.</p>
<p>This is not specific to Solidity. In fact, reverting state changes upon
unsuccessful termination <em>for the failed call only</em> is the default mode
of operation for the EVM. Solidity doesn’t have <code class="highlighter-rouge">try-throw-catch</code> yet,
just <code class="highlighter-rouge">throw</code>, so <a href="https://solidity.readthedocs.io/en/latest/control-structures.html#exceptions">the compiler wraps every external call</a>
in a structure that makes the parent fail if the child failed, – to
stay on the safe side. I applaud those who had the foresight.</p>
<p>Also, did you know? The guaranteed failure of a <code class="highlighter-rouge">throw</code> is achieved
by <code class="highlighter-rouge">JUMP</code>ing to an invalid destination.</p>
<h2 id="external-is-a-keyword-primer----skip-if-acquainted"><code class="highlighter-rouge">external</code> is a keyword (primer – skip if acquainted)</h2>
<p>The under-used feature mentioned before is a function visibility
specifier, <code class="highlighter-rouge">external</code>. It marks a function as “to be used by other
dapps, not this one”. From the <a href="https://solidity.readthedocs.io/en/v0.3.5/control-structures.html#external-function-calls">docs</a>:</p>
<blockquote>
<p>The expression this.g(8); is also a valid function call, but this time,
the function will be called “externally”, via a message call and
not directly via jumps. Functions of other contracts have to be called
externally. For an external call, all function arguments have to be
copied to memory.</p>
</blockquote>
<p>(The docs currently lack an example use case.)</p>
<p>Why isn’t it used much?</p>
<p>Probably because functions are <code class="highlighter-rouge">public</code> by default; meaning their
signatures are available for other dapps to use, and external calls
is the only way dapps do it. Making function F <code class="highlighter-rouge">external</code> instead of
<code class="highlighter-rouge">public</code> in dapp D prevents the developer of D from making direct calls
to it (via <code class="highlighter-rouge">JUMP</code>s on assembly level), but the outside developer can
still <code class="highlighter-rouge">D.F()</code> just the same. <code class="highlighter-rouge">external</code> limits the developer of D, but
not everybody else, so its usefulness is not self-evident.</p>
<p>An “external call” manifests on the blockchain as an “internal transaction”
(counter-intuitive phrasing, yes) from account A to account B,
with gas (and possibly value) attached. EVM-wise, arguments are pushed
to memory, “depth counter” is incremented, and control is transferred.
If execution succeeds, return values are pushed to memory, and control
is returned (together with all remaining gas). If execution fails,
all performed state changes are rolled back, and control is returned
(remaining gas, if any, is consumed).</p>
<h2 id="application-the-trick----read-and-understand">Application (the trick – read and understand)</h2>
<p>By making an external call to itself, a dapp could have an isolated
part that either executes as expected, or not at all. “As expected”,
of course, is loaded, since the expectations need to be specified
somewhere.</p>
<p>(<strong>UPDATE 2016-08-09</strong>: it’s been <a href="https://www.reddit.com/r/ethereum/comments/4wsn8t/conditionally_cancelling_part_of_a_dapps_state/d6a94a2">noted</a> that
<code class="highlighter-rouge">external</code> is not needed to make an “external call”. It is useful
in this case, however, to prevent making an internal call by accident.)</p>
<p>Here’s a proof of concept (<a href="https://github.com/veox/solidity-dapps/blob/master/ThisExternalAssembly/ThisExternalAssembly.sol">also on GitHub</a>, or
<a href="https://veox.pw/dump/ThisExternalAssembly.html">pygmentized</a>). Details after the code.</p>
<p>(<strong>UPDATE 2016-10-16</strong>: using assembly is not required, a Solidity
<code class="highlighter-rouge">.call()</code> can be performed instead. I find it useful here to demonstrate
what’s going on under the hood.)</p>
<p><code class="highlighter-rouge">ThisExternalAssembly.sol</code>:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">contract</span> <span class="nx">ThisExternalAssembly</span> <span class="p">{</span>
<span class="nx">uint</span> <span class="kr">public</span> <span class="nx">numcalls</span><span class="p">;</span>
<span class="nx">uint</span> <span class="kr">public</span> <span class="nx">numcallsinternal</span><span class="p">;</span>
<span class="nx">uint</span> <span class="kr">public</span> <span class="nx">numfails</span><span class="p">;</span>
<span class="nx">uint</span> <span class="kr">public</span> <span class="nx">numsuccesses</span><span class="p">;</span>
<span class="nx">address</span> <span class="nx">owner</span><span class="p">;</span>
<span class="nx">event</span> <span class="nx">logCall</span><span class="p">(</span><span class="nx">uint</span> <span class="nx">indexed</span> <span class="nx">_numcalls</span><span class="p">,</span> <span class="nx">uint</span> <span class="nx">indexed</span> <span class="nx">_numcallsinternal</span><span class="p">);</span>
<span class="nx">modifier</span> <span class="nx">onlyOwner</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span> <span class="o">!=</span> <span class="nx">owner</span><span class="p">)</span> <span class="k">throw</span><span class="p">;</span> <span class="nx">_</span> <span class="p">}</span>
<span class="nx">modifier</span> <span class="nx">onlyThis</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span> <span class="o">!=</span> <span class="nx">address</span><span class="p">(</span><span class="k">this</span><span class="p">))</span> <span class="k">throw</span><span class="p">;</span> <span class="nx">_</span> <span class="p">}</span>
<span class="c1">// constructor</span>
<span class="kd">function</span> <span class="nx">ThisExternalAssembly</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">owner</span> <span class="o">=</span> <span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">failSend</span><span class="p">()</span> <span class="nx">external</span> <span class="nx">onlyThis</span> <span class="nx">returns</span> <span class="p">(</span><span class="nx">bool</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// storage change + nested external call</span>
<span class="nx">numcallsinternal</span><span class="o">++</span><span class="p">;</span>
<span class="nx">owner</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="mi">42</span><span class="p">);</span>
<span class="c1">// placeholder for state checks</span>
<span class="k">if</span> <span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="k">throw</span><span class="p">;</span>
<span class="c1">// never happens in this case</span>
<span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">doCall</span><span class="p">(</span><span class="nx">uint</span> <span class="nx">_gas</span><span class="p">)</span> <span class="nx">onlyOwner</span> <span class="p">{</span>
<span class="nx">numcalls</span><span class="o">++</span><span class="p">;</span>
<span class="nx">address</span> <span class="nx">addr</span> <span class="o">=</span> <span class="nx">address</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="nx">bytes4</span> <span class="nx">sig</span> <span class="o">=</span> <span class="nx">bytes4</span><span class="p">(</span><span class="nx">sha3</span><span class="p">(</span><span class="s2">"failSend()"</span><span class="p">));</span>
<span class="nx">bool</span> <span class="nx">ret</span><span class="p">;</span>
<span class="c1">// work around `solc` safeguards for throws in external calls</span>
<span class="c1">// https://ethereum.stackexchange.com/questions/6354/</span>
<span class="nx">assembly</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">x</span> <span class="err">:</span><span class="o">=</span> <span class="nx">mload</span><span class="p">(</span><span class="mh">0x40</span><span class="p">)</span> <span class="c1">// read "empty memory" pointer</span>
<span class="nx">mstore</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="nx">sig</span><span class="p">)</span>
<span class="nl">ret</span> <span class="p">:</span><span class="o">=</span> <span class="nx">call</span><span class="p">(</span>
<span class="nx">_gas</span><span class="p">,</span> <span class="c1">// gas amount</span>
<span class="nx">addr</span><span class="p">,</span> <span class="c1">// recipient account</span>
<span class="mi">0</span><span class="p">,</span> <span class="c1">// value (no need to pass)</span>
<span class="nx">x</span><span class="p">,</span> <span class="c1">// input start location</span>
<span class="mh">0x4</span><span class="p">,</span> <span class="c1">// input size - just the sig</span>
<span class="nx">x</span><span class="p">,</span> <span class="c1">// output start location</span>
<span class="mh">0x1</span><span class="p">)</span> <span class="c1">// output size (bool - 1 byte)</span>
<span class="c1">//ret := mload(x) // no return value ever written :/</span>
<span class="nx">mstore</span><span class="p">(</span><span class="mh">0x40</span><span class="p">,</span><span class="nx">add</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="mh">0x4</span><span class="p">))</span> <span class="c1">// just in case, roll the tape</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">ret</span><span class="p">)</span> <span class="p">{</span> <span class="nx">numsuccesses</span><span class="o">++</span><span class="p">;</span> <span class="p">}</span>
<span class="k">else</span> <span class="p">{</span> <span class="nx">numfails</span><span class="o">++</span><span class="p">;</span> <span class="p">}</span>
<span class="c1">// mostly helps with function identification if disassembled</span>
<span class="nx">logCall</span><span class="p">(</span><span class="nx">numcalls</span><span class="p">,</span> <span class="nx">numcallsinternal</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// will clean-up :)</span>
<span class="kd">function</span> <span class="nx">selfDestruct</span><span class="p">()</span> <span class="nx">onlyOwner</span> <span class="p">{</span> <span class="nx">selfdestruct</span><span class="p">(</span><span class="nx">owner</span><span class="p">);</span> <span class="p">}</span>
<span class="kd">function</span><span class="p">()</span> <span class="p">{</span> <span class="k">throw</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Here, <code class="highlighter-rouge">doCall()</code> is just a wrapper to work around Solidity’s security
mechanism, whereas <code class="highlighter-rouge">failSend()</code> demonstrates utility of the approach.</p>
<p>Note that <code class="highlighter-rouge">failSend()</code>:</p>
<ul>
<li>can <em>only</em> be called externally due to the <code class="highlighter-rouge">external</code> specifier;</li>
<li>can’t be called by other dapps because of the <code class="highlighter-rouge">onlyThis</code> modifier.</li>
</ul>
<p>In effect, it can only be called by the same contract, via an external
call.</p>
<p>The function body is all placeholders to increase readability. In a
“real” compratmentalised call, one would first perform checks, preferably
via modifiers; then changes to contract storage; then nested external
calls. That is, the check-change-send routine.</p>
<p>After that, one would perform “state checks” and look for unexpected
state changes, for all accounts touched by this function. If there are
any discrepancies, changes resulting from all nested calls can be
reverted – at the cost of gas initially passed to the call. The rest of
the contract can continue execution.</p>
<p>This is far from fool-proof. Re-entrancy checks would still be required,
along with everything else we have and haven’t yet come up with. But it
demonstrates a feature of Solidity not yet available, namely exception
handling – admittedly, in a convoluted manner.</p>
<p>(<strong>UPDATE 2016-08-11</strong>: an <a href="https://steemit.com/ethereum/@veox/conditionally-cancelling-part-of-a-dapp-s-state-changes#@nikolai/re-veox-conditionally-cancelling-part-of-a-dapp-s-state-changes-20160810t145115423z">exception-like technique</a>
has been brought to my attention that provides functionatilty similar to
<code class="highlighter-rouge">try-catch-finally</code>.)</p>
<h2 id="its-alive-testing----read-and-verify">It’s alive! (testing – read and verify)</h2>
<p>I’ve deployed the dapp on ETH main-net (see <a href="https://etherscan.io/address/0x6abd2b75ff5f306a4d99bfab1ff84b57bb9d23e7">etherscan.io</a> or
<a href="https://live.ether.camp/account/6abd2b75ff5f306a4d99bfab1ff84b57bb9d23e7">live.ether.camp</a>). There were a few failed iterations,
and then a final working one on Morden test-net, but I couldn’t get the
block explorers to validate code there, so had to re-deploy the final on
main-net again.</p>
<p>Set up <code class="highlighter-rouge">geth</code>:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="o">></span> <span class="kd">var</span> <span class="nx">demoaddr</span> <span class="o">=</span> <span class="s2">"0x6abd2b75ff5f306a4d99bfab1ff84b57bb9d23e7"</span><span class="p">;</span>
<span class="o">></span> <span class="kd">var</span> <span class="nx">demoabi</span> <span class="o">=</span> <span class="o"><</span><span class="nx">snipped</span><span class="o">></span><span class="p">;</span>
<span class="o">></span> <span class="kd">var</span> <span class="nx">d</span> <span class="o">=</span> <span class="nx">eth</span><span class="p">.</span><span class="nx">contract</span><span class="p">(</span><span class="nx">demoabi</span><span class="p">).</span><span class="nx">at</span><span class="p">(</span><span class="nx">demoaddr</span><span class="p">);</span></code></pre></figure>
<p>Storage variables after creation:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="o">></span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">d</span><span class="p">.</span><span class="nx">numcalls</span><span class="p">(),</span> <span class="nx">d</span><span class="p">.</span><span class="nx">numcallsinternal</span><span class="p">(),</span> <span class="nx">d</span><span class="p">.</span><span class="nx">numfails</span><span class="p">(),</span> <span class="nx">d</span><span class="p">.</span><span class="nx">numsuccesses</span><span class="p">())</span>
<span class="o">></span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span></code></pre></figure>
<p>Run <code class="highlighter-rouge">doCall()</code> once, then check variables:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="o">></span> <span class="kd">var</span> <span class="nx">lasttx</span> <span class="o">=</span> <span class="nx">d</span><span class="p">.</span><span class="nx">doCall</span><span class="p">(</span><span class="mi">50000</span><span class="p">,</span> <span class="p">{</span><span class="na">from</span><span class="p">:</span> <span class="nx">owneraddr</span><span class="p">,</span> <span class="na">value</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="na">gas</span><span class="p">:</span> <span class="mi">200000</span><span class="p">})</span>
<span class="o">></span>
<span class="o">></span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">d</span><span class="p">.</span><span class="nx">numcalls</span><span class="p">(),</span> <span class="nx">d</span><span class="p">.</span><span class="nx">numcallsinternal</span><span class="p">(),</span> <span class="nx">d</span><span class="p">.</span><span class="nx">numfails</span><span class="p">(),</span> <span class="nx">d</span><span class="p">.</span><span class="nx">numsuccesses</span><span class="p">())</span>
<span class="o">></span> <span class="mi">1</span> <span class="mi">0</span> <span class="mi">1</span> <span class="mi">0</span></code></pre></figure>
<p>As expected, <code class="highlighter-rouge">failSend()</code> threw, so <code class="highlighter-rouge">numcallsinternal++</code> got reverted.
42 wei that were initially passed to <code class="highlighter-rouge">doCall()</code> <a href="https://etherscan.io/tx/0x2f26e4a8ca335bd4097fe719f38d39f72fd109bafabf97e96fa33d9d5d4d5fe8">remained with the
dapp</a>.</p>
<h2 id="donate-please-do">Donate (please do)</h2>
<p>Decided to try <a href="https://steemit.com/ethereum/@veox/conditionally-cancelling-part-of-a-dapp-s-state-changes">Steemit</a> to see how much I’d get rewarded.
<a href="https://veox.pw/">Other ways</a> are preferred, though.</p>
<p>Research, testing and writing the article took ~ 12 hours.</p>
TheDAOHardForkOracle - an Ethereum hard-fork oracle, live before the forkveox2016-07-18T00:00:00+03:00https://wemakethings.net/2016/07/18/thedaohardforkoracle<h2 id="intro">Intro</h2>
<p>An oracle is a dapp that can provide information to other dapps,
code external to the blockchain(s), and people.</p>
<p>With a hard-fork imminent for Ethereum, there needs to be a way
to reliably determine which <a href="https://en.wikipedia.org/wiki/Tine_(structural)">tine</a> (chain) one is on.</p>
<p>There are not many solutions I’ve seen so far - actually, just
<a href="https://medium.com/@timonrapp/how-to-deal-with-the-ethereum-replay-attack-3fd44074a6d8#32c4">this one</a> by Timon Rapp. Although, to be honest, I wasn’t
looking that much, and this seemed a good exercise anyway.</p>
<h2 id="how-this-oracle-should-work">How this oracle should work</h2>
<p>It has to answer one question:</p>
<blockquote>
<p>Is this the “classic” or the “hard-fork” chain?</p>
</blockquote>
<p>That is reasonably simple. However, complications:</p>
<ol>
<li>it can’t answer “both”, at any time;</li>
<li>it shouldn’t have a default answer;</li>
<li>it could answer “none”, but only before the fork;</li>
<li>the code must be identical, no matter the answer;</li>
<li>the address must be identical;</li>
<li>it would be very nice if the answer was available ASAP, preferably
same block as the fork, please.</li>
</ol>
<h2 id="critique">Critique</h2>
<p>Barring the discovery of some yet-unknown vunerability in TheDAO
that would allow draining the DarkDAO off-shoot pre-fork, Timon’s solution
kind-of-fits the requirements above. <code class="highlighter-rouge">1</code>, <code class="highlighter-rouge">2</code> and <code class="highlighter-rouge">3</code> are guaranteed
and <strong>can be verified pre-fork</strong>.</p>
<p>Caveats:</p>
<ul>
<li>it uses the constructor to determine the answer, and
therefore must be deployed after the fork. Its address is not known
pre-fork, so code relying on the answer can’t be deployed before that.</li>
<li>It must be simultaneously deployed on both chains, and that requires
“transaction hygiene” <a href="https://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed">to ensure that the oracle address is the
same</a>
on both chains.</li>
<li>On the up-side, it can be deployed by anyone. On the down-side, that
could mean repetition of effort.</li>
</ul>
<p>Pretty solid. Since we already have that, I wanted to try something else.</p>
<h2 id="code">Code</h2>
<p>It’s <a href="https://github.com/veox/solidity-dapps/blob/TheDAOHardForkOracle-v0.1/TheDAOHardForkOracle/TheDAOHardForkOracle.sol">available on GitHub</a>, and
<strong>is already deployed on the pre-fork blockchain</strong> (see
<a href="https://etherscan.io/address/0xe8e506306ddb78ee38c9b0d86c257bd97c2536b3">etherscan.io</a> and <a href="https://live.ether.camp/account/e8e506306ddb78ee38c9b0d86c257bd97c2536b3">live.ether.camp</a>).</p>
<p><code class="highlighter-rouge">TheDAOHardForkOracle.sol</code>:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">contract</span> <span class="nx">TheDAOHardForkOracle</span> <span class="p">{</span>
<span class="nx">address</span> <span class="nx">constant</span> <span class="nx">WithdrawDAO</span> <span class="o">=</span> <span class="mh">0xbf4ed7b27f1d666546e30d74d50d173d20bca754</span><span class="p">;</span>
<span class="nx">address</span> <span class="nx">constant</span> <span class="nx">DarkDAO</span> <span class="o">=</span> <span class="mh">0x304a554a310c7e546dfe434669c62820b7d83490</span><span class="p">;</span>
<span class="c1">// public, so accessors available</span>
<span class="nx">bool</span> <span class="kr">public</span> <span class="nx">ran</span><span class="p">;</span>
<span class="nx">bool</span> <span class="kr">public</span> <span class="nx">forked</span><span class="p">;</span>
<span class="nx">bool</span> <span class="kr">public</span> <span class="nx">notforked</span><span class="p">;</span>
<span class="nx">modifier</span> <span class="nx">after_dao_hf_block</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">block</span><span class="p">.</span><span class="nx">number</span> <span class="o"><</span> <span class="mi">1920000</span><span class="p">)</span> <span class="k">throw</span><span class="p">;</span>
<span class="nx">_</span>
<span class="p">}</span>
<span class="nx">modifier</span> <span class="nx">run_once</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">ran</span><span class="p">)</span> <span class="k">throw</span><span class="p">;</span>
<span class="nx">_</span>
<span class="p">}</span>
<span class="nx">modifier</span> <span class="nx">has_millions</span><span class="p">(</span><span class="nx">address</span> <span class="nx">_addr</span><span class="p">,</span> <span class="nx">uint</span> <span class="nx">_millions</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">_addr</span><span class="p">.</span><span class="nx">balance</span> <span class="o">>=</span> <span class="p">(</span><span class="nx">_millions</span> <span class="o">*</span> <span class="mi">1000000</span> <span class="nx">ether</span><span class="p">))</span> <span class="nx">_</span>
<span class="p">}</span>
<span class="c1">// 10M ether is ~ 2M less than would be available for a short</span>
<span class="c1">// while in WithdrawDAO after the HF, but probably more than</span>
<span class="c1">// anyone is willing to drop into WithdrawDAO in Classic</span>
<span class="kd">function</span> <span class="nx">check_withdrawdao</span><span class="p">()</span> <span class="nx">internal</span>
<span class="nx">has_millions</span><span class="p">(</span><span class="nx">WithdrawDAO</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">forked</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// failsafe: if the above assumption is incorrect, HF tine</span>
<span class="c1">// won't have balance in DarkDAO anyway, and Classic has a</span>
<span class="c1">// sliver of time before DarkDAO split happens</span>
<span class="kd">function</span> <span class="nx">check_darkdao</span><span class="p">()</span> <span class="nx">internal</span>
<span class="nx">has_millions</span><span class="p">(</span><span class="nx">DarkDAO</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">notforked</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// running is possible only once</span>
<span class="c1">// after that the dapp can only throw</span>
<span class="kd">function</span> <span class="p">()</span>
<span class="nx">after_dao_hf_block</span> <span class="nx">run_once</span> <span class="p">{</span>
<span class="nx">ran</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="nx">check_withdrawdao</span><span class="p">();</span>
<span class="nx">check_darkdao</span><span class="p">();</span>
<span class="c1">// if both flags are same, then something went wrong</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">forked</span> <span class="o">==</span> <span class="nx">notforked</span><span class="p">)</span> <span class="k">throw</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h2 id="does-it-fit-the-requirements">Does it fit the requirements?</h2>
<p>Well, not exactly. Putting a fork oracle onto the chain pre-fork means
another possible answer is introduced - “pre-fork”. The answer is no
longer binary. One must work around that either by returning a
numeric/symbolic answer, or by answering two questions.</p>
<p>This dapp does the latter by having flags <code class="highlighter-rouge">ran</code> and <code class="highlighter-rouge">forked</code> (<code class="highlighter-rouge">notforked</code>
is redundant, but can be conveniently used, too). They are <code class="highlighter-rouge">public</code>,
meaning the Solidity compiler automatically produces accessors (value
return functions) for them.</p>
<p>By default, <code class="highlighter-rouge">bool</code> variables are <code class="highlighter-rouge">false</code>. The fallback function is
prohibited to run prior the fork (<a href="https://etherscan.io/tx/0x656526fc0d8396ed21781c8d4f831afdee1576fe57dab50d971b8343eca8f191">tested that</a>). Prior
to the fork, <code class="highlighter-rouge">ran()</code> is guaranteed to return <code class="highlighter-rouge">false</code>, but so are the
other two - fitting complication <code class="highlighter-rouge">2</code> above.</p>
<p><code class="highlighter-rouge">1</code> and <code class="highlighter-rouge">3</code> are moot, and using <code class="highlighter-rouge">forked()</code> without <code class="highlighter-rouge">ran()</code> means
trouble pre-fork and some time after, until it is general knowledge
that the dapp works as intended.</p>
<p><code class="highlighter-rouge">4</code> and <code class="highlighter-rouge">5</code> are guaranteed and <strong>can be verified pre-fork</strong>.</p>
<p><code class="highlighter-rouge">6</code> has the same gothcha as Timon’s solution. Two clients have to be
automated to send a transaction on respective tines of the fork.</p>
<h2 id="why-two-conditions">Why two conditions?</h2>
<p>This hard fork will make certain alterations to the state of the EVM.
Namely, moving ether from some accounts to another.</p>
<p>(More on this in my <a href="https://pay.reddit.com/r/ethereum/comments/4qr0jm/eli5_how_does_the_actual_hf_consensus_mechanism/d4vauj7">post on Reddit</a> some time ago - it’s
dated and doesn’t reflect the current spec exactly, but is non-technical
enough).</p>
<p>One condition checks if the refund dapp has indeed been refunded. The
other checks if the known split dapp still has its share. A successful
hard-fork, I would argue, involves the former being met, but not the
latter; and a successful continuation of the pre-fork state - the other
way around.</p>
<p>That, and I was trying to work around complication <code class="highlighter-rouge">2</code> above. Different
than <a href="/2016/07/16/failed_challenge_2_sweeping_dapp/">my previous attempt at writing Solidity</a>, it’s
all on <a href="https://github.com/veox/solidity-dapps/commits/master">GitHub</a>.</p>
<p>It does introduce an attack vector, though: anyone can drop 10
million ether into <code class="highlighter-rouge">WithdrawDAO</code>’s account, pre-fork (yeah, right) or
post-fork on the “classic” chain. Then this dapp couldn’t reliably
determine which chain it’s on (on one of the fork’s tines), rendering
it useless (on both tines).</p>
<p>As with Timon’s dapp, “some yet-unknown vunerability in TheDAO
that would allow draining the DarkDAO off-shoot pre-fork” would result
in the same failure.</p>
<h2 id="conclusion">Conclusion</h2>
<p>So, there you go. Do you need to run some dapp on block #190005, but
deploy it before the fork? Now you can. Make sure to check <code class="highlighter-rouge">ran()</code>,
though, or send a transaction first if you’re dire.</p>
<p>Any attached ether will be locked forever. This is intentional, since
some (dated?) clients don’t allow sending 0 ether.</p>
<h2 id="liked-this">Liked this?</h2>
<p>The dapp and article took ~ 8 hours to write and check, since I’m new
and slow.</p>
<p>If you’d like to donate, check <a href="https://veox.pw/">my drop page</a>.</p>
Failed Challenge 2 sweeping dappveox2016-07-16T00:00:00+03:00https://wemakethings.net/2016/07/16/failed_challenge_2_sweeping_dapp<h2 id="intro-challenge-1">Intro: Challenge 1</h2>
<p>Sjors Provoost has put up <a href="https://medium.com/@dao.challenge/challenge-1-296cb5dab68f">the original challenge</a>
with the intent “to hone [his] skills at writing secure smart contract
code.” He funded the contract with ~ 9.5 ETH for there to be a
real bounty for completing the challenge (i.e. hacking it).
<a href="https://etherscan.io/address/0xBe56093286038885733a66e554DD43a22a45889f#code">The code</a> is simple and doesn’t leave much to
imagination, though.</p>
<p>…It even keeps the money if the receiving end is another dapp that
does, well, almost anything. That has become “classic” fast, in both
theoretical attack vectors, and practical malicious ones.</p>
<p>However, it could also be normal for a well-meaning dapp. These
days, it’s a wallet. But say you’re a self-flying postal drone
trying to withdraw the client’s tokens to pay for electricity, and
doing some accounting in the process. Remember, as a drone you don’t
get to send your own transactions, and might as well piggy-back on
client-initiated transactions (if you know the token you’re withdrawing
uses <code class="highlighter-rouge">call()</code> instead of <code class="highlighter-rouge">send()</code>).</p>
<h2 id="vulnerable-challenge-2">Vulnerable: Challenge 2</h2>
<p>Anyway, Sjors put <a href="https://medium.com/@dao.challenge/challenge-2-a749c4158023">another challenge up</a>, and funded it
with ~ 10 ETH, that should allow for described behaviour. In that, he
had this:</p>
<p><code class="highlighter-rouge">DaoChallenge (segment)</code>:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// This uses call.value()() rather than send(), but only sends to msg.sender</span>
<span class="kd">function</span> <span class="nx">withdrawEtherOrThrow</span><span class="p">(</span><span class="nx">uint256</span> <span class="nx">amount</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">bool</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span><span class="p">.</span><span class="nx">call</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="nx">amount</span><span class="p">)();</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">result</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>In the Ethereum language Solidity, all functions are <code class="highlighter-rouge">public</code> by default.
<code class="highlighter-rouge">public</code> functions can be called by anyone - that is, any account.</p>
<p>The obvious way to sweep this contract would then be to
start an Ethereum client, load the contract’s ABI, and call
<code class="highlighter-rouge">withdrawEtherOrThrow(...)</code> with the desired amount.</p>
<p>The day before I found a <a href="https://github.com/PeterBorah/smart-contract-security-examples/issues/3">possible 50/50 drain vector</a> in
Peter Borah’s <code class="highlighter-rouge">TokenWithInvariants</code> example; I couldn’t provide
code then, since I didn’t know the dapp deployment procedure, and
had done zero actual Solidity programming. This time, I decided I’d
write a contract to do the sweep. Here it is, in the form <a href="https://etherscan.io/address/0x6a3120d8a66fe96eb260cce4b6da02e7835b8426#code">it’s been
deployed</a> onto the blockchain.</p>
<p><code class="highlighter-rouge">chal2sweep.sol</code>:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">contract</span> <span class="nx">chal2sweep</span> <span class="p">{</span>
<span class="nx">address</span> <span class="nx">chal</span> <span class="o">=</span> <span class="mh">0x08d698358b31ca6926e329879db9525504802abf</span><span class="p">;</span>
<span class="nx">address</span> <span class="nx">noel</span> <span class="o">=</span> <span class="mh">0x1488e30b386903964b2797c97c9a3a678cf28eca</span><span class="p">;</span>
<span class="c1">// restrict msg.sender</span>
<span class="nx">modifier</span> <span class="nx">only_noel</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span> <span class="o">==</span> <span class="nx">noel</span><span class="p">)</span> <span class="nx">_</span> <span class="p">}</span>
<span class="c1">// don't run recursively</span>
<span class="nx">modifier</span> <span class="nx">msg_value_not</span><span class="p">(</span><span class="nx">uint</span> <span class="nx">_amount</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">msg</span><span class="p">.</span><span class="nx">value</span> <span class="o">!=</span> <span class="nx">_amount</span><span class="p">)</span> <span class="nx">_</span>
<span class="p">}</span>
<span class="c1">// could use kill() straight-up, but want to test gas on live chain</span>
<span class="kd">function</span> <span class="nx">withdraw</span><span class="p">(</span><span class="nx">uint</span> <span class="nx">_amount</span><span class="p">)</span> <span class="nx">only_noel</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">noel</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">_amount</span><span class="p">))</span> <span class="k">throw</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// should allow withdrawal without gas calc</span>
<span class="kd">function</span> <span class="nx">kill</span><span class="p">()</span> <span class="nx">only_noel</span> <span class="p">{</span>
<span class="nx">suicide</span><span class="p">(</span><span class="nx">noel</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// web3.toWei(10, "ether") == "10000000000000000000"</span>
<span class="kd">function</span> <span class="p">()</span> <span class="nx">msg_value_not</span><span class="p">(</span><span class="mi">10000000000000000000</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">chal</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="s2">"withdrawEtherOrThrow"</span><span class="p">,</span> <span class="mi">10000000000000000000</span><span class="p">))</span>
<span class="k">throw</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>The interesting part is, of course, the fallback function (the nameless
one). It should have worked like this:</p>
<ol>
<li>I send a transaction from account <code class="highlighter-rouge">noel</code> with anything but 10 ether
attached to it.</li>
<li><code class="highlighter-rouge">chal2sweep</code> makes a call to the vulnerable <code class="highlighter-rouge">DaoChallenge</code> method
and requests a withdrawal of 10 ether.</li>
<li><code class="highlighter-rouge">DaoChallenge</code> honours the request and sends it to <code class="highlighter-rouge">msg.sender</code>,
which is again <code class="highlighter-rouge">chal2sweep</code>.</li>
<li>That hits the fallback function of <code class="highlighter-rouge">chal2sweep</code> again, but since the
amount is exactly 10 ether, the body is not executed.</li>
</ol>
<p>The code is also available in <a href="https://github.com/veox/solidity-dapps/blob/master/chal2sweep/chal2sweep.sol">this repo</a>, along
with a <a href="https://github.com/veox/solidity-dapps/blob/master/oneline.sh">simple script</a> to do deployment copy-pasting into
<code class="highlighter-rouge">geth</code>.</p>
<p>Any updates I do to it will be pushed there. Of those, I can immediately
think of:</p>
<ul>
<li>being able to change the target address - although this is kind of
useless without being able to specify the target’s vulnerable function,
and perhaps the amount;</li>
<li>using the <code class="highlighter-rouge">only_noel</code> modifier instead of <code class="highlighter-rouge">msg_value_not(...)</code> - after
all, I only want my calls to result in further malicious calls.</li>
</ul>
<h2 id="oops">Oops</h2>
<p>I never got to test if that code works as intended, because <a href="http://etherscan.io/tx/0xfe329d21c206a111ab393ad74627d9cf1338852daa65542963c1dd13138152b5">someone
beat me to it</a>. In particular, I never got to test if
<code class="highlighter-rouge">chal.call("withdrawEtherOrThrow", 10000000000000000000)</code> is the correct
syntax.</p>
<p>It was somewhat disappointing that some schmuck, who probably even wouldn’t
share his exploit, beat me to it by <a href="https://etherscan.io/tx/0x710a65ef029cd95dbb76db9ab190d113b7e3813410d0a8f0449f08ff8abc0689">less than 30 minutes</a>.
(I assumed it was a “schmuck”, since they didn’t come public immediately
after - not on <a href="https://medium.com/@dao.challenge/challenge-2-a749c4158023">Medium</a>, <a href="https://pay.reddit.com/r/ethereum/comments/4rc2un/please_rob_my_smart_contract/">Reddit</a>, or
<a href="https://github.com/Sjors/dao-challenge/issues?q=is:issue">GitHub</a>.)</p>
<p>It <a href="https://github.com/Sjors/dao-challenge/issues/1">turned out</a>, however, that it was
<a href="https://medium.com/@dao.challenge/challenge-3-how-i-almost-lost-100-1a11a9824ccb">Sjors himself</a>. He was working on a new challenge, and
remembered he forgot something in the old one.</p>
<h2 id="fallout">Fallout</h2>
<p>In retrospect, a de-facto bug bounty is much motivation for entry-level
people like myself. No one in their right minds would hire us for
fixed-salary code audit, but money on the line is good enough for
all-or-nothing, learn-as-you-go activities.</p>
<p>I might just fire up a testnet node again to test all my sloppy code.
And other folk’s, too.</p>
Just passing throughffwd2016-06-03T00:00:00+03:00https://wemakethings.net/2016/06/03/just_passing_through<p>There was once this space-faring civilization that decided to take their
calling to the limit. They said they would push for the stars.</p>
<p>Now, spacetime is tricky, and requires a lot of energy to traverse.
The best source of energy is mass, and to go anywhere at all you need
something at least the size of Jupiter.</p>
<p>So they packed their stuff on a boat, collapsed the sun, and uploaded
themselves to a matrix with its last dying rays. The view was fabulous,
you should have seen it.</p>
<p>Scans showed a few promising locations with lifeless rocks and gas
giants. Enough to keep the mind occupied, the vessel stocked, and nobody
to care about the ruckus left behind. They would plot the course many
jumps ahead, and took great care to avoid loops. Orbits get hairy fast
if you turn a constant that’s been there for billions of years into a
variable. Most politics revolved around where to go next.</p>
<p>They’ve been to a binary black hole once. A few planets in the early
stage of formation. Thousands of other ex-homeworlds that just “didn’t
make it”, now desolate and dead. And between each “next big thing”, they
left a wake of disarrayed solar systems - orbital mechanics best studied
from afar.</p>
<p>Every once in a while, they’d meet another civilization that did the
exact same thing. It was customary to exchange representatives, charts,
points of interest, and rumors.</p>
<p>The most common one was that of a bar, but nobody’s actually been there,
since it moved around fairly often. The only way to get in was to wait
in its path. And nobody’s ever left to tell if it’s any good.</p>
<hr />
<p>This time, they were passing through a fairly generic neighborhood. All
of a sudden, one of the systems lit up. It was a narrow corridor anyway,
one star to the next to the next. There was no way around it, so they
went forward.</p>
<p>What they found was a civilization in the early stages of
self-discovery. There was much debate as to whether “stay and study” or
“put them out of their misery and pretend it never happened”.</p>
<p>Long story short, they parked behind the moon.</p>
<p>Contact was inevitable, but highly problematic: it’s hard to tell the
host you’ll be going now, and taking the house with you. Compounding
this was the fact that the visitors had originally been small, green,
and lizard-like. Although they didn’t have to look like anything
in particular by then, it still sometimes showed.</p>
<p>And these sorts of young, visual civilizations pay too much attention
to style.</p>
Torch lamp shaderxdtxd2016-05-30T00:00:00+03:00https://wemakethings.net/2016/05/30/lamp_shade<p>While the conscientious crew was spreading maker fear this weekend, I
finally got around to doing some home improvement.</p>
<p>I found this crappy torchièr in the dumpster a couple of years ago. It
was lacking shades, so I wrapped some aluminum foil around the bulb, and
that’s been my reading fixture ever since.</p>
<p>Recently (about 1,5 years ago) I found another one, mostly identical
to the first, with a more stable base (that is, a larger piece of
concrete). It, too, was lacking shades.</p>
<p>For this one, I thought, I’m not going to cheap out on materials. I’m
going to use copper. It’s going to be round, with a hole at the top (for
the bulb), and easy on the eyes. It’s going to be great.</p>
<p>So, I stripped the insulation off of some power cables that were too
short to use anywhere else. (More on that in a different post.)</p>
<p><img src="/assets/images/2016-05-29-lamp_shade/01-wire.jpg" alt="Copper wires without insulation, some bent into circles" /></p>
<p>Bending copper is pretty easy!..</p>
<p><img src="/assets/images/2016-05-29-lamp_shade/02-wire_sun.jpg" alt="Wires affixed to a small base ring" /></p>
<p>… straightening it - not so much. I’ve only
done this a few times before, and even then never had to affix the wires
to each other. Wrapping them is a lot of work, and even then there’s
too much slippage.</p>
<p>At some point, the thing started to look too much like a dream-catcher for
nightmares.</p>
<p><img src="/assets/images/2016-05-29-lamp_shade/03-dreamcatcher.jpg" alt="Nightmare-catcher" /></p>
<p>The globe wireframe certainly didn’t work. It crumbled under my gaze.</p>
<p>So I tried concentric circles a-la gyroscope instead (the mickey mouse
shape on the bottom theoretically threads onto the bulb socket):</p>
<p><img src="/assets/images/2016-05-29-lamp_shade/04-pliers_orb.jpg" alt="Wireframe orb held together by friction" /></p>
<p>Pretty good! But still takes too long. I was kind of wishing for a
rolling mill and a spot welder by then, but settled on a known-round
shape and a soldering iron. Took apart the hand-wrought “orb”, too -
copper is precious, and there’s only so much to go around.</p>
<p>In comes the torchièr base:</p>
<p><img src="/assets/images/2016-05-29-lamp_shade/06-base_and_wires.jpg" alt="Round base used for wire rolling" /></p>
<p>Post-factum, I probably should have used the paper bin instead.
It’s slightly conic, and would have produced concentric circles of
ever-so-slightly bigger size. Easier to fit into one another.</p>
<p>Anyway, here’s the soldered variant:</p>
<p><img src="/assets/images/2016-05-29-lamp_shade/07-soldered_orb.jpg" alt="Wireframe orb held together by solder" /></p>
<p>Again, it took a while to make - a vise or such would have helped. After
that, though, adding more circles is a breeze. Here’s a total of seven:</p>
<p><img src="/assets/images/2016-05-29-lamp_shade/08-soldered_orber.jpg" alt="Wireframe orb with a lot more wire" /></p>
<p>Not exactly geometrically homogeneous, but certainly not lacking is
symbolism.</p>
<p><img src="/assets/images/2016-05-29-lamp_shade/09-soldered_illuminati.jpg" alt="PRAISE THE LORD" /></p>
<p>That “socket thread” looks kind of like a quasi-mystical cult symbol of
some sort. Coincidence?.. I don’t think so.</p>
<p>For the actual shade material, I used a quarter roll of painters’ tape.
Rolling it on was a grind, have some tubes ready if you’re going to
repeat it.</p>
<p><img src="/assets/images/2016-05-29-lamp_shade/12-finished_closeup.jpg" alt="Hey! I'm a moon!.. :D" /></p>
<p>There! No arduino, no wifi, no spinning motors, no RGB LEDs, no dimming,
no 3D-printed parts. Switch-operated. Probably a bug trap. Casts a light
triangle on the ceiling.</p>
Floor controlled lighting and the OrbnightshadeEglėiochpwf2016-02-01T00:00:00+02:00https://wemakethings.net/2016/02/01/lights<p>A few months ago <em>Eglė</em> asked me for help with an installation she wanted to
build for the exhibition <em>neLIESTI</em>. The basic idea: on the floor of a room an array of
switches, activated by stepping on them. The switches control various lights
around the room independently. The array is 3 x 7, for a total of 21 channels.
The lights included incandescent, halogen bulbs, flourescent tubes, LEDs and the
<a href="#orb">Orb</a>.</p>
<p>The exhibition was open during the month of December, 2015 in <em>šv. Jono gatvės
galerija</em>. Some relevant links:</p>
<ul>
<li><a href="https://www.facebook.com/events/825842110866058/">Facebook event</a></li>
<li><a href="http://www.lrt.lt/naujienos/kultura/26/123762#wowzaplaystart=2472000&wowzaplayduration=206000">LRT video report</a></li>
<li><a href="http://www.satenai.lt/2016/01/15/egles-ir-birutes-pojuciu-kambariai/">Šiaurės atėnai</a></li>
<li><a href="http://www.bernardinai.lt/straipsnis/2015-12-29-keli-vizualumo-variantai-ir-metu-uzbaigimas/139068">Bernardinai</a></li>
</ul>
<p><strong>Navigation:</strong> <a href="#floor-switches">Floor switches</a> | <a href="#orb">Orb</a> | <a href="#caustic-hoist">Caustic hoist</a></p>
<h2 id="floor-switches">Floor switches</h2>
<p><img src="/assets/images/2016-02-01-lights/lights.jpg" alt="Finished" /></p>
<p><em>Eglė</em> had and idea for the basic button design: an about 37 x 37 x 8 cm
plywood box-in-a-box, with pieces of soft polyester glued to the top part. They
act as a spring. The button can be pushed down with one foot by most people.</p>
<p><img src="/assets/images/2016-02-01-lights/prototype.jpg" alt="Prototype" /></p>
<p>We were considering making custom electrical contacts out of spring steel strips
(rulers), but settled on mechanical limit switches with a springy lever, as used
on machine endstops. They are rated for mains voltage therefore no additional
indirection is required. The switches have a tactile ‘click’ that can be faintly
felt through the box.</p>
<p><img src="/assets/images/2016-02-01-lights/switch.jpg" alt="Switch" /></p>
<p>The switch sits on a standoff so that it’s top is about where the edges of the
bottom box are. When the top box is pushed to the bottom it pushes the lever.
Because the lever is springy the vertical position of the switch doesn’t need to
be very precise. I used a few rough templates to cut, drill, glue and screw
the standoffs and switches consistently, which went pretty fast.</p>
<p>Wires are connected with crimp connectors to enable disassembly.</p>
<p><img src="/assets/images/2016-02-01-lights/array.jpg" alt="Array" /></p>
<p>The buttons are bolted to a plywood base which houses the wires: a 0.75
mm<sup>2</sup> common (red) for each 7-button row and a 0.5 mm<sup>2</sup>
return (gray) from each button. I calculated the sizes for about 150W max per
light.</p>
<p><img src="/assets/images/2016-02-01-lights/knot.jpg" alt="Knot" /></p>
<p>The wires go to an electrical box that I called the ‘knot’. It routes the
switches to 2x0.5 mm<sup>2</sup> cables (black), one for each light. I used
almost 200 m of these for the ~5x6m room. The wiring took a few days.</p>
<p>Each cable has a label that describes the light. The final step was matching the
lights with buttons in the array in an interesting way.</p>
<p><img src="/assets/images/2016-02-01-lights/labels.jpg" alt="Labels" /></p>
<hr />
<h2 id="orb">Orb</h2>
<p><img src="/assets/images/2016-02-01-lights/arch.jpg" alt="Arch" /></p>
<p>One of the lights to be controlled was the Orb: a programmable 100W RGB LED that
<em>ioch</em> and I made a while ago. We typically use it as a disco light/strobe. It’s
controlled by a few potentiometers and a tap-tempo button. DMX control is in the
to-do list. For this occasion I removed the interactivity from the program and
it just randomly changes the hue ten times per second, while keeping brightness
and saturation at maximum.</p>
<p><img src="/assets/images/2016-02-01-lights/orb.jpg" alt="Orb" /></p>
<p>The LED is mounted on a CPU heatsink with a fan. Each RGB channel is driven by
an LDD-1000HW 1A constant current supply. It has an ‘off’ pin that is PWMed from
an Arduino. The power supply is 48V 3A switching mode: each channel requires
over 30V to even turn on (because it is actually many LEDs in series). The
Arduino and fan are powered by a separate ‘12V’ supply</p>
<p>The source is <a href="https://github.com/kspi/orb">on Github</a>. The simplified version
is in the ‘svjonogallery’ branch.</p>
<p>If you have interesting ideas for the Orb, write me an email.</p>
<p>GIF animation (click to play):</p>
<p><img id="orbgif" src="/assets/images/2016-02-01-lights/orb_static.gif" /></p>
<script language="javascript" type="text/javascript">
(function(){
var urlplay = '/assets/images/2016-02-01-lights/orb.gif';
var urlstop = '/assets/images/2016-02-01-lights/orb_static.gif';
var img = document.getElementById('orbgif');
(new Image()).src = urlplay; // preload
function togglegif() {
if (img.src.indexOf('static') != -1) {
img.src = urlplay;
} else {
img.src = urlstop;
}
}
img.onclick = togglegif;
})();
</script>
<hr />
<h2 id="caustic-hoist">Caustic hoist</h2>
<p>Another installation in the exhibition was a halogen bulb mounted above an array
of jars, moving vertically up and down, casting moving caustics onto the room
below.</p>
<p>The bulb was hung on a rope (actually a piece of soft cable), tied to a steel
drum that <em>pwf</em> made and mounted on a windshield wiper motor. I reused the
electronics from the <a href="/2015/05/22/twisting-tubes/">twisting tubes project</a> and
programmed them for different speed and duration of movement.</p>
<video width="700" controls="controls" preload="metadata" poster="/assets/images/2016-02-01-lights/caustics.jpg">
<source src="https://wemakethings.net/assets/videos/lights.webm" type="video/webm" /></source>
<source src="https://wemakethings.net/assets/videos/lights.mp4" type="video/mp4" /></source>
<img alt="Caustics" src="/assets/images/2016-02-01-lights/caustics.jpg" />
</video>
LEDs got waxed - a blinken lights installation for stagemiceuz2015-12-25T00:00:00+02:00https://wemakethings.net/2015/12/25/leds-got-waxed<iframe width="853" height="480" src="https://www.youtube.com/embed/2exLmgqX1m4?rel=0" frameborder="0" allowfullscreen="1">.</iframe>
<p>A local band called “<a href="https://www.youtube.com/user/Sheepgotwaxed">Sheep got waxed</a>” has approached me with a proposal to create some interactive stage lighting effects. It had to be transportable and adaptable to different stage settings. Well, what can one do? Let’s blink them LEDs! We agreed to make 16 individually controllable white LED strips and distribute them amongst the musicians, playing animations trigerred by the music being played.</p>
<p>The first requirements description of the system went like this:</p>
<blockquote>
<ul>
<li>3 differential pro-line level audio inputs each for one channel</li>
<li>16 LED outputs</li>
<li>5, 5, 6 LEDS assigned to channels</li>
</ul>
<p>Audio level trigger is automatically set to 2/3 of full range.</p>
<p>One of 5 effects can be assigned to each channel by the means of a rotary switch, one potentiometer is available for each channel that is used to control an aspect of the selected effect</p>
<p>Available effects:
* VU meter - LEDs blink as in an audio VU meter, the potentiometer controls the total brightness
* Triggered VU meter - channels light up and turn down in a row on a trigger, just like VU meter. Potentiometer controls the speed of the effect.
* Chase - channels light up one by one in a row when triggered. Potentiometer controls the speed of the animation.
* Blink - all channels fade in and fade out simultaneously on trigger. Potentiometer controls the speed of the fading.
* Random - all channels blink randomly for a duration set by potentiometer.</p>
</blockquote>
<p><img src="/assets/images/2015-12-25-tlc5945.jpg" alt="TLC5945 dimmer" /></p>
<p>For the main controller I’ve chosen the <a href="https://www.tindie.com/products/miceuz/led-pwm-dimmer/">TLC5945 breakout board</a> I made recently. TLC5945 is a nice chip providing 16 channels of 12-bit PWM goodness. The board has a socket for Arduino Nano, a footprint for RS485 transceiver and a bunch of screw terminals.</p>
<p>THAT1247 was chosen as the audio front end. It’s a go-to no-brainer part when you want to do a differential line level signal translation. I did not want a journey while rolling my own, so I picked this part. I used a 6dB part and configured it as an amplifier to increase signal level. This is what the point-to-point soldered board looks:
<img src="/assets/images/2015-12-25-audio-frontend.jpg" alt="Audio input PCB" /></p>
<p><img src="/assets/images/2015-12-25-audio-input.png" alt="Audio input" /></p>
<p>The U2A opamp creates the virtual ground midpoint. U1 receives a differential pair and creates a single-ended signal around virtual ground. Single ended signal is AC coupled and limited by diode D1 to apply only positive peaks to ADC input. Capacitor C3 and resistor R4 form an antialiasing low-pass filter which is buffered by U2B. R5 and D2 are there to protect MCU ADC input from overvoltage. I was going to run ADC at 250kHz, this allowed me to sample three channels at roughly 6kHz, this means our Nyquist frequency is 3kHz – that’s what determined my choice of R4 and C3.</p>
<p>This is what it looks on the scope, yellow and blue are inputs, magenta is what an MCU sees:
<img src="/assets/images/2015-12-25-audio-frontend-scope.jpg" alt="Audio input" /></p>
<p>The segments had to be put on the floor at 45 degree angle. I have had a go with OpenSCAD to model the 3D printed stands for them. This was the first thing I’ve ever designed and printed.</p>
<p><img src="/assets/images/2015-12-25-foot.png" alt="Foot" /></p>
<p>Since we have plenty of those, I have used a Chinese Ebay “LED amplifier” on each strip. Inside it looks like a dumbed-down RGB dimmer version with a Chinese microcontroller and a MOSFET. It acts like a transistor - when you power a pin, it switches the other two on. As one needs to provide at least 12V to switch, they are robust enough - no crosstalk problems whatsoever when running 6 channels on one cable.</p>
<p>Wiring is a mess as I couldn’t think a of good way to provide power and data to strips with quick-disconnect connectors, so I made it the dumb way. 2x0.75mm<sup>2</sup> cable was used for 12V and 8 wire UTP for control lines.</p>
<p><img src="/assets/images/2015-12-25-strips-and-wiring.jpg" alt="LED strips and wiring" /></p>
<p>In the middle of the project I have decided to ditch the switch and potentiometer idea - musicians have enough stuff to do on stage anyway and lighting is a job of the lighting engineer. All the parameters of the effects now were to be controlled via DMX from lighting console. That’s where having a spare RS485 footprint became handy. A thing to note - audio XLR inputs are female by convention, but DMX inputs are male! I did not expect that, so I had to make this adapter to hook up the DMX.</p>
<p><img src="/assets/images/2015-12-25-male-to-male.jpg" alt="Male to male XLR" /></p>
<p>I used the 74HC165 serial shift in register to read the dip switch for the DMX address and test modes. This didn’t work in the beginning as it appeared that the SPI comm was breaking TLC comm somehow. There was no time to debug that since we were going live in a couple of days and those couple of days were the Christmas Eve and co. So I gfell back to bitbanging to read the dip switch. It seemed the SPI bus could not be used while the TLC chip library is actively pushing data.</p>
<p>Then I assembled everything into a box. I’ve tried my best, but not every part is pretty, especially the square holes.</p>
<p><img src="/assets/images/2015-12-25-in-the-box.jpg" alt="In the box" /></p>
<p>I have leveraged a wonderful program QLC+ for control - we worked together with the band and the light engineer to expose as many means as possible for controlling the effects over DMX :
- Effect – the effect style
- Trigger level – the level of audio which triggers the effect
- Trigger hold off – time to now trigger after triggering
- Decay speed – how fast the effect fades
- Master – max brightness level
- Gain – audio input level multiplier</p>
<p><img src="/assets/images/2015-12-25-qlc-console.jpg" alt="QLC" /></p>
<p>All in all everything went as expected except for a couple of hot fixes I had to make just before the show and a crash. I must say I still hate the wiring - a battery-operated wireless solution would have been a proper thing to do. All the code and documentation is on <a href="https://github.com/Miceuz/leds-got-waxed">my github</a></p>
<p><img src="/assets/images/2015-12-25-banner.jpg" alt="LEDs got waxed" /></p>
<p><img src="/assets/images/2015-12-25-live.jpg" alt="Live on stage" />
Foto by <a href="https://www.facebook.com/nphtgrph/">No Photography</a></p>
A low-end automated household plant watering systemrxdtxd2015-07-13T00:00:00+03:00https://wemakethings.net/2015/07/13/pumpensau<p>I have a chronic condition which doesn’t allow me to leave home for more than 12 hours at a time. It’s called “plants”. These plants need watering. And although <em>miceuz</em>’s made a wonderful <a href="/chirp/">gadget</a> to remind <strike>neighbours of your incompetence</strike> you when it needs to be done, it’s not so useful if there’s but a few short evenings to figure it all out and put the thing together.</p>
<p>So, a few weeks ago…</p>
<p><img src="/assets/images/2015-07-13-1-system.jpg" alt="Window with plants and installed pumpensau" /></p>
<p>Nettles (on the left) are the most resilient. They can survive for a week with zero attention, and even if they wither, they don’t really die. Pour some water, they’ll start over. I cannot praise them enough to all my green-thumb friends. Make sure you follow the example and put them near a window handle.</p>
<p>Tomatoes (center) and chili plants (right)… not so much.</p>
<p>Dilles (invisible in the sunspot, see last image) are a fluke from last year. They survived the winter and earned their place under the sun. There’s also some citrus tree in one of the pots, but you won’t see it ‘cause it’s small. (I was lazy one day and dumped the juicer’s leftovers into the pot instead of the trashbin.)</p>
<p>What’s this contraption made of? Actually, simple stuff! Most components are readily-available in any bourgeois household, or can be sourced from local sweatshops in the real world.</p>
<p><img src="/assets/images/2015-07-13-2-test.jpg" alt="Single module under test" /></p>
<p>The above proof-of-concept setup consists of an electric current source, a tiny pump (with genuine hoses), a water source, a pot simulation unit, and a DIY capillary-effect-drip-sponge-thingie.</p>
<p>Here’s a closer view on the second iteration:</p>
<p><img src="/assets/images/2015-07-13-3-test.jpg" alt="Single module under test with a longer hose" /></p>
<p>The pump I’m using here came from eBay or something, but <em>pwf</em> assures me they can be scavenged from toy dolls that piss themselves when groomed.</p>
<p>In the previous image, you can see I’m using a longer hose (also from the internets). It’s a tad stiffer than the genuine hose, so the pump takes longer to prime, but that can be worked around manually (i.e. suck the output for a few seconds).</p>
<p>I’ve later discovered that a saline solution drip bag (raid the pharmacy) comes with a nice long tube that has a fitting adapter for the genuine hose. It’s fast, cheap, and you get a bag of hangover remedy as a bonus.</p>
<p>Now, the water disseminator…</p>
<p><img src="/assets/images/2015-07-13-4-sponge.jpg" alt="Drip sponge assembly" /></p>
<p>…took a few attempts to get right, but it’s basically a straw with holes, with a water retainer around it. Water comes in at one end, the tube fills up, and (since the other end is jammed) water drips out through the holes, soaking up its surroundings.</p>
<p>Here, I’ve used a plastic cocktail straw and kitchen sponges, but an actual plant straw and some rags can be used just as well, I guess.</p>
<p>For the first two sponge sticks, I’ve removed the stiffer scrubbing surface, but later discovered this is unnecessary and undesirable, as it reduces rigidity. I also figured that holes in the straw can lie on a straight line, so water will only come out when the straw is full (if horisontal). The scrubbing surface is then also useful to mark which side is the “top”.</p>
<p>Here’s <strong>a tip</strong>: you can’t burn through the sponge with a soldering iron or hot nail to put the tube in. That would melt the porous sponge, making it impermeable. I used a brass tube, sharpened at one end, to “drill” out holes for the straw, in small increments (which is why the sponge is chopped into short manageable parts).</p>
<p>Now, I have three pots to water, and three pumps. I tried finding a power source in our bin to feed all three, but couldn’t. So I used three random chargers instead.</p>
<p><img src="/assets/images/2015-07-13-5-power.jpg" alt="Power distribution" /></p>
<p>The pumps are rated at 6 volts, the chargers are between 4.3V and 7.3V. I plugged the beefy one to water tomatoes, and the meek one to water nettles.</p>
<p>On the other end of the cable, there’s a household timer like this one:</p>
<p><img src="/assets/images/2015-07-13-6-timer.jpg" alt="Timer" /></p>
<p>Experimentally I’ve found that my pumps use up half a liter each in about 10 minutes. That’s about as much water as the tomatoes get per 12 hours. However, since it’s not me pouring to each his own over the entire pot, I’ve split the timings into 4 episodes, 3 minutes each. Excessive water usage by the nettles and chili plants is unfortunate, but not game-ending.</p>
<p>I was going away for 2-5 days, so a largish water tank was necessary:</p>
<p><img src="/assets/images/2015-07-13-7-tank.jpg" alt="Water tank" /></p>
<p>I found this one in a garbage container. It had some washing fluid leftovers, so I washed the toilet, kind of. I’m quite proud of it, being so thrifty and all.</p>
<p>When it came time to install the whole thing, I just stuck the drip sponge in the middle like so (making sure it’s more or less horisontal):</p>
<p><img src="/assets/images/2015-07-13-8-pot.jpg" alt="Sponge in a pot" /></p>
<p>…About four days later, the water tank was empty, but the little green people all survived.</p>
<p><img src="/assets/images/2015-07-13-9-chillie.jpg" alt="Chili plants" /></p>
<p>Again, I could’ve used <a href="/chirp/">chirp!</a>, but I wanted something very simple very fast. Maybe next time.</p>
Parabol: 3D printed laptop standnightshade2015-06-19T00:00:00+03:00https://wemakethings.net/2015/06/19/parabol-laptop-stand<p><img src="/assets/images/2015-06-19-parabol.jpg" alt="Parabol" /></p>
<p>Before putting a laptop on our workshop table one has to wipe a layer of
dust, resistor lead clippings and miscellaneous components off it. It is
not the best surface for a laptop with cooling intake at the bottom, so
a stand would be useful, I thought.</p>
<p>I searched the internet a bit, but didn’t find any ready made printable
models, mostly just templates for laser cutting. I started sketching in
Wings 3D, but settled on a simpler idea.</p>
<p><img src="/assets/images/2015-06-19-parabol-top-side.png" alt="Top and side templates" /></p>
<p>I drew two templates in Inkscape: a top view (the parabol) and a side
view, and wrote a short OpenSCAD script that extrudes and intersects the
templates to obtain the three-dimensional shape.</p>
<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="c1">// This should be the same as DXF_SCALE in the Makefile.
</span><span class="n">dxf_scale</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span>
<span class="n">depth</span> <span class="o">=</span> <span class="mi">1000</span><span class="p">;</span> <span class="c1">// Extrusion depth
</span><span class="n">intersection</span><span class="p">()</span> <span class="p">{</span>
<span class="n">linear_extrude</span><span class="p">(</span><span class="n">height</span><span class="o">=</span><span class="n">depth</span><span class="p">)</span>
<span class="n">scale</span><span class="p">(</span><span class="mi">1</span> <span class="o">/</span> <span class="n">dxf_scale</span><span class="p">)</span> <span class="n">import</span><span class="p">(</span><span class="n">file</span><span class="o">=</span><span class="s">"top.dxf"</span><span class="p">);</span>
<span class="n">rotate</span><span class="p">(</span><span class="mi">90</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
<span class="n">rotate</span><span class="p">(</span><span class="mi">90</span><span class="p">,</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
<span class="n">linear_extrude</span><span class="p">(</span><span class="n">height</span><span class="o">=</span><span class="n">depth</span><span class="p">)</span>
<span class="n">scale</span><span class="p">(</span><span class="mi">1</span> <span class="o">/</span> <span class="n">dxf_scale</span><span class="p">)</span> <span class="n">import</span><span class="p">(</span><span class="n">file</span><span class="o">=</span><span class="s">"side.dxf"</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p><img src="/assets/images/2015-06-19-parabol-model.png" alt="Model" /></p>
<p>The model size is about 240x240x78mm and it fits my 14” laptop well. It
is approaching the bed size of our TAZ 4 printer: 298x275x250mm. The
angle is pretty comfortable, although maybe a bit steep for a lot of
typing. Structurally it’s pretty bendy around the Z axis. That could be
fixed by adding a horizontal strut (making the top view an A shape), but
it doesn’t matter that much when a laptop is on top.</p>
<p>The sources and final STL model are available <a href="https://github.com/kspi/parabol">on
Github</a>. To build it just run <code class="highlighter-rouge">make</code>.
It also requires <em>pstoedit</em> which is used to convert SVG to DXF.</p>
<hr />
<p><strong>Update:</strong> <em>bLynx</em> created her own version of the laptop stand by modifying the
SVGs and rebuilding the model. It is less steep, has a horizontal bar for more
stiffness and longer hooks to fit her computer. She also glued some leather
strips on top so the laptop doesn’t slide around.</p>
<p><img src="/assets/images/2015-06-19-parabol-blynxs-top.jpg" alt="bLynx's stand - top" />
<img src="/assets/images/2015-06-19-parabol-blynxs-side.jpg" alt="bLynx's stand - side" /></p>
bitcoin-server launch wrapperveox2015-05-24T00:00:00+03:00https://wemakethings.net/2015/05/24/bitcoin-server-wrapper<p>I’m running <code class="highlighter-rouge">libbitcoin</code>’s <a href="libbitcoin-server">bitcoin-server</a> on a VPS with 1 GB of RAM and 512 MB of swap, which is clearly not enough. The server starts getting killed for reaching an out-of-memory condition every minute or so after block #200000, even on Testnet.</p>
<p>It’s dirty and it clogs up fast, but it works.</p>
<p>Every OOM kill adds to the possibility of database corruption. So I sometimes back it up, too.</p>
<p><code class="highlighter-rouge">/home/veox/bin/run-bs</code>:</p>
<figure class="highlight"><pre><code class="language-sh" data-lang="sh"><span class="c">#!/bin/sh</span>
<span class="c"># bitcoin-server launch wrapper</span>
<span class="c"># restarts the server if it gets OOM-killed</span>
<span class="k">while </span><span class="nb">true</span>; <span class="k">do
if</span> <span class="o">[</span> <span class="s2">"x</span><span class="sb">`</span>pidof bs<span class="sb">`</span><span class="s2">"</span> <span class="o">=</span> <span class="s2">"x"</span> <span class="o">]</span>; <span class="k">then
</span><span class="nb">cd</span> /home/veox/testnet
/usr/sbin/logrotate -s ./bs.logrotate.status ./bs.logrotate
/home/veox/usr/bin/bs /home/veox/usr/etc/libbitcoin/bs.cfg
<span class="k">fi
</span>sleep 10
<span class="k">done</span></code></pre></figure>
<p><code class="highlighter-rouge">/home/veox/testnet/bs.logrotate</code>:</p>
<figure class="highlight"><pre><code class="language-sh" data-lang="sh">/home/veox/testnet/error.log /home/veox/testnet/debug.log <span class="o">{</span>
size 1M
missingok
notifempty
rotate 21
<span class="o">}</span></code></pre></figure>
<p><code class="highlighter-rouge">/home/veox/testnet/bs.logrotate.status</code>:</p>
<figure class="highlight"><pre><code class="language-sh" data-lang="sh"><span class="s2">"/home/veox/testnet/error.log"</span> 2015-5-24-21:22:55
<span class="s2">"/home/veox/testnet/debug.log"</span> 2015-5-24-21:22:55</code></pre></figure>
LED swordrxdtxd2015-05-23T00:00:00+03:00https://wemakethings.net/2015/05/23/led-sword<p><img src="/assets/images/2015-05-23-18-white_and_markers.jpg" alt="LED sword" /></p>
<p>I’ve been commisioned to make six LED swords for aspiring jedi accolytes. I have been given three days to accomplish this task. The timeframe means no specific orders from China, and overpaying for everything.</p>
<p>What I ended up with was a reasonably wobbly object consisting of:</p>
<ul>
<li>for the blade, a square aluminum pipe mounted inside a round plexiglass tube, and RGB LED strips in between (60 LEDs per meter);</li>
<li>for the handle, an aluminum pipe and a 3D-printed insert cap; the handle stores batteries, the cap holds color switches;</li>
<li>a separately-controllable set of white LED “markers” on both ends of the blade;</li>
<li>in between, lots of glue;</li>
<li>all over, lots of wires.</li>
</ul>
<p>Here’s a few photos from the build log.</p>
<p>First, the shop didn’t have enough RGB LEDs on hand, so I had a lot of time to do everything else. I made a lot of wires like these:</p>
<p><img src="/assets/images/2015-05-23-02-quad_wires.jpg" alt="One-to-many split wires" /></p>
<p>They connect the LED strips like so:</p>
<p><img src="/assets/images/2015-05-23-01-marker_stages.jpg" alt="LED strip connections" /></p>
<p>The handle, as I mentioned, had a simple 3D-printed cap for the buttons, and a very nice one-piece battery holder for 8 AAs. That, and some wires.</p>
<p><img src="/assets/images/2015-05-23-05-handle_assembly.jpg" alt="Handle assembly" /></p>
<p>I first thought of printing the whole handle, but that would have taken too long.</p>
<p>A close-up on the “button panel”:</p>
<p><img src="/assets/images/2015-05-23-06-buttons.jpg" alt="Buttons" /></p>
<p>When the RGB LED strips finally arrived, I could solder pre-made wire assemblies right in:</p>
<p><img src="/assets/images/2015-05-23-07-quads_soldered.jpg" alt="Wires soldered to RGB LED strips" /></p>
<p>The handle is square, the blade is round. How does one connect square and round? It didn’t have to be airtight in this case, and no astronaut would die heroically if it wasn’t. So I just wrapped a lot of paper around the blade, secured it with duct tape, …</p>
<p><img src="/assets/images/2015-05-23-03-handle_and_tube.jpg" alt="Square vs. round" /></p>
<p>… pushed it into the handle, and poured in copious amounts of hot glue.</p>
<p><img src="/assets/images/2015-05-23-08-handles_glued.jpg" alt="Handles filled with glue" /></p>
<p>A few more rolls of electric tape later, this is what I got:</p>
<p><img src="/assets/images/2015-05-23-09-blank.jpg" alt="LED sword (off)" /></p>
<p>Pure colors are pretty nice:</p>
<p><img src="/assets/images/2015-05-23-10-red.jpg" alt="LED sword (red)" />
<img src="/assets/images/2015-05-23-11-green.jpg" alt="LED sword (green)" />
<img src="/assets/images/2015-05-23-12-blue.jpg" alt="LED sword (blue)" /></p>
<p>The white markers look like this:</p>
<p><img src="/assets/images/2015-05-23-13-markers.jpg" alt="LED sword (markers)" /></p>
<p>Mixed colors are funky - not all segmets of LED strips are made equal:</p>
<p><img src="/assets/images/2015-05-23-14-yellow.jpg" alt="LED sword (yellow)" />
<img src="/assets/images/2015-05-23-15-magenta.jpg" alt="LED sword (magenta)" />
<img src="/assets/images/2015-05-23-16-cyan.jpg" alt="LED sword (cyan)" /></p>
<p>And white (compare to the same with markers at the very top):</p>
<p><img src="/assets/images/2015-05-23-17-white.jpg" alt="LED sword (white)" /></p>
<p>This is what the blade tip looks like:</p>
<p><img src="/assets/images/2015-05-23-20-far_end_pipe.jpg" alt="Blade tip" /></p>
<p>The other end:</p>
<p><img src="/assets/images/2015-05-23-21-handle_end.jpg" alt="How do you call this part where the handle meets the blade? Tell me please." /></p>
<p>Magic control buttons:</p>
<p><img src="/assets/images/2015-05-23-22-buttons.jpg" alt="User interface buttons on the bottom of the handle" /></p>
Twisting tubesnightshadeEglė2015-05-22T00:00:00+03:00https://wemakethings.net/2015/05/22/twisting-tubes<p>Me and <em>pwf</em> have been working with Eglė Lekevičiūtė on her art installation.
It’s part of her exhibition called Ratais Kvadratais, open May 13 to June 30th
at <a href="http://www.vaikugalerija.lt/">Vaikų galerija</a>.</p>
<p>It consists of two sets of bicycle wheels mounted on opposing walls. One
side of the set has wheels and a motor connected with a long chain,
while the other side has corresponding stationary wheels connected with
a tube of cloth. There is one motor on each wall and the wheels
of the sets are interspersed.</p>
<p><img src="/assets/2015-05-22-whole.jpg" alt="Whole" /></p>
<p><strong>Movement.</strong> The target speed of the motor changes like a sine wave
with a period of about a minute, though slightly different for each
motor. They start synchronously, but slowly drift apart and back, in and
out of phase. Due to the lack of feedback the actual speed is also
influenced by changing friction, which is essentially unpredictable
due to the complex and unreliable system of wheels and chain.</p>
<p><em>pwf</em> welded cogs directly to the wheel hubs.</p>
<p>The biggest challenge is making the chain work reliably. This requires mounting
the wheels on a flat plane, tuning the bearings and applying just enough
tension on the chain. One of the gallery walls is not completely flat so we had
problems making that side turn consistently.</p>
<video width="800" controls="controls" preload="metadata">
<source src="https://wemakethings.net/assets/videos/twisting-tubes.webm" type="video/webm" /></source>
<source src="https://wemakethings.net/assets/videos/twisting-tubes.mp4" type="video/mp4" /></source>
Your browser does not support the video tag.
</video>
<p><strong>Electronics.</strong> We used 12V windshield wiper motors. They have an
integrated transmission with a low gear ratio, therefore a slow speed,
but high torque. To control the motors’ speed and direction
independently, I built a driver using a pair of L298 chips. The chip has
two channels each rated for 2A, while the motors require about 2-3A, so
I bridged the two channels of each chip together. The driver is
connected to a microcontroller which does open loop control. I used a recycled
computer PSU for power.</p>
<p>I made a few stupid mistakes building the electronics, but eventually figured
everything out, with help from <em>mic</em>. <em>ioch</em> helped me etch the circuit board.</p>
<p><img src="/assets/2015-05-22-driver.jpg" alt="Driver" />
<img src="/assets/2015-05-22-motor.jpg" alt="Motor" /></p>
Replacing TAZ 4 extruder heaternightshade2015-04-30T00:00:00+03:00https://wemakethings.net/2015/04/30/taz-extruder-heater<p>We won a <a href="https://www.lulzbot.com">LulzBot</a> TAZ 4 3D printer at their
hackerspace giveaway. It had a few issues, namely the encoder steps not exactly
corresponding to menu actions and the bed always staying 1°C below target
temperature, which I set out to fix.</p>
<p>They publish a modified version of the Marlin firmware as an archive on the
downloads page. They also have a <a href="https://github.com/alephobjects/Marlin">Github
repo</a>, but I did not find a version
corresponding to our printer there.</p>
<p>While messing with the firmware I burned out the 6W “heating resistor” on the
extruder, by setting the max PWM value too high. Instead of buying an exact
replacement, I opted for a 40W heating element from our parts bin. It’s
slightly smaller than the hole on the extruder, so I spaced it with some
aluminum foil and fixed it in place with kapton tape.</p>
<p><img src="/assets/images/2015-04-30-heater-replacement.jpg" alt="Heater replacement" /></p>
<p><a href="https://github.com/Technariumas/Marlin_TAZ4">Our firmware modifications are available on
Github</a>. The temperature detection
code is improved, the encoder issue fixed, and PID values tuned for our
printer. Here it is printing a soap holder and some checkers:</p>
<p><a href="/assets/images/2015-04-30-printing-big.jpg"><img src="/assets/images/2015-04-30-printing.jpg" alt="Printing" /></a></p>
<p><small>I also added a custom logo:</small></p>
<p><img src="/assets/images/2015-04-30-logo.jpg" alt="Technarium logo" /></p>
How to make Z0 probe and see those sharp edgesmiceuz2014-12-23T00:00:00+02:00https://wemakethings.net/2014/12/23/z0_probe<p><img src="/assets/images/2014-12-23-header.jpg" alt="Z0 probe" /></p>
<p>For a future project I was playing with a basic oscillator, based on inverter and ceramic resonator.</p>
<p><img src="/assets/images/2014-12-23-inverter-oscillator-schematics.png" alt="Z0 probe" /></p>
<p>After hooking everything up on a breadboard and looking at the signal I have instatly understood it’s the fast signal domain
and shonky breadboard will not cut it, so I have soldered everything on a copper clad board.</p>
<p><img src="/assets/images/2014-12-23-inverter-oscillator.jpg" alt="Z0 probe" /></p>
<p>The signal looked like this. Eww where are those overshoots comming from? In spite of signal being just 12MHz, the edges of the
pulses are too sharp for my measurement system to record properly.</p>
<p><img src="/assets/images/2014-12-23-overshoots.jpg" alt="Z0 probe" /></p>
<p>First things first. Let’s have a look at what power looks like. Wow, this looks really bad. Oscillator produces really sharp
edges demanding huge gulps of current. Inductance in naively long leads of decoupling capacitors causes power rail to bounce aroud
pretty awfully.</p>
<p><img src="/assets/images/2014-12-23-power.jpg" alt="Z0 probe" /></p>
<p>After shortening the leads, power rail looks much better. Peaks are cut in half.</p>
<p><img src="/assets/images/2014-12-23-power2.jpg" alt="Z0 probe" /></p>
<p>I had 100uF electrolytic and 10 uF ceramic capacitors for decoupling. Let’s add small capacitance to take care of those sharp edges.
After adding 1nF ceramic cap, power rail looks even better.</p>
<p><img src="/assets/images/2014-12-23-power3.jpg" alt="Z0 probe" /></p>
<p>Ok, let’s get back to the output signal. I was scoping the signal with 50MHz Rigol DS1052E scope, using stock Rigol probe that claims
to be of 100MHz bandwidth. The probe was in X10 mode and I’ve used a short spring for the ground connection. There is less overshoot
than in the picture above, but still, I’d like to get rid of it.</p>
<p><img src="/assets/images/2014-12-23-overshoots2.jpg" alt="Z0 probe" /></p>
<p>The rising edge of the signal is about 4 - 5 ns. According to the internets, to see such an edge I’d need 1/(pi * trise) ~70MHz of
bandwidth. Of course this is impossible with 50MHz scope, but I wanted to do something about those overshoots anyway.
Scope probe even in X10 mode has a fair amount of capacitance that plays with sharp edges and causes ringing and overshoots. Z<sub>0</sub> low impedance probe to the rescue!
If you want to see sharp signal edges, you have to reduce capacitance in the probe, this simple probe does just that.</p>
<p>To make a Z<sub>0</sub> probe, you’ll need a length of 50Ω coaxial cable, a coax connector, 450Ω resistor and 50Ω terminator
if your scope does not have 50Ω input option.</p>
<p>As I didn’t have 450Ω resistor I’ve shuffled thru my stash of 470Ω resistors to find 462Ω one. This gives me X9.7 ratio - close
enough to standard X10. To make a probe, just solder the resistor to the end of coax cable and put the connector to the other end.
To properly terminate 50Ω cable, add a terminator at the connector end. Now you have a high speed probe.</p>
<p><img src="/assets/images/2014-12-23-z0.jpg" alt="Z0 probe" /></p>
<p>Yellow trace in this picture is Z<sub>0</sub> probe, blue trace stock Rigol probe in X10 mode with short ground lead.
As you can see, overshoots are completely gone with Z<sub>0</sub> probe.</p>
<p><img src="/assets/images/2014-12-23-z0-comparison.jpg" alt="Z0 probe" /></p>
Wayward shrine at the Burning Manopitaugustedinamakiprasmiceuzpwfvarious artists2014-11-22T00:00:00+02:00https://wemakethings.net/2014/11/22/wayward_shrine<p>We wanted to bring something of our own to the Burning Man besides the <a href="http://wemakethings.net/2014/06/23/pieva/">Silicone Meadow</a> installation. Wayward shrines, or <a href="https://en.wikipedia.org/wiki/Stogastulpis">stogastulpiai</a>, are traditional micro-shrines erected on pillars next to the settlements and roads at this part of the world. Usually they have religious figures inside, as well as strong pagan elements.</p>
<p><em>pwf</em> and <em>Ieva</em> had been joking about making an anti-shrine. Me and <em>miceuz</em> thought that we might do something interesting with this idea and eventually decided to make a shrine containing artefacts that would serve as commentaries on the current realities of Lithuania. I did the design part, <em>miceuz</em> was responsible for electronics.</p>
<p>We knew we would be able to use an industrial CNC router in Reno, so I decided to use Google Sketchup to make the model which we would cut out of plywood. Here’s a concept sketch:</p>
<p><img src="/assets/images/2014-11-22-sketch.jpg" alt="First sketch" /></p>
<p>I drew a cactus-like main structure because we were talking about fractals at the time. All the patterns were inspired by actual ethnographic shrines – they’re really beautiful (and short-lived) pieces of mini-architecture.</p>
<p><img src="/assets/images/2014-11-22-ethno1.jpg" alt="Real shrines" /></p>
<p><img src="/assets/images/2014-11-22-ethno2.jpg" alt="Real shrines" />
(via <a href="https://www.google.com/search?safe=off&site=&tbm=isch&source=hp&biw=1366&bih=601&q=koplytstulpis&oq=koplytstulpis">Google image search</a>)</p>
<p>Making the blueprints took me a while, because I had absolutely no experience with any 3D modelling program whatsoever. Here’s the overall model:</p>
<p><img src="/assets/images/2014-11-22-skp_all.jpg" alt="Sketchup draft" /></p>
<p>And the exploded elements:</p>
<p><img src="/assets/images/2014-11-22-skp_exploded.jpg" alt="Sketchup draft" /></p>
<p>Once we were at the <a href="http://therenogenerator.com/">Generator</a>, we cut the parts out of birch plywood. Massive thanks to Jeremy for letting us use his router and all technical and logistical help!</p>
<p>Then <em>pwf</em>, <em>miceuz</em>, <em>dinama</em>, me and <em>kipras</em> sanded, glued and nailed the main three parts of the shrine together and packed them for the journey to the desert. I darkened the plywood surface using <a href="http://www.friendly-home.net/2012/07/finishing-how-to-oxidize-wood.html">the vinegar and iron oxide</a> method. Worked like a charm. Here’s the main pole drying out:</p>
<p><img src="/assets/images/2014-11-22-painting.jpg" alt="Painting" /></p>
<p>We built the shrine next to our camp. Here’s how it looked at daytime:
<img src="/assets/images/2014-11-22-camp.jpg" alt="Container" />
(picture by R. Požerskis)</p>
<p>At night, it was lit with an WS2812 LED strip, controlled via a <a href="https://www.pjrc.com/teensy/">Teensy</a>. We bought a goat skull on ebay and put it inside the main shrine. That seemed like an obvious thing to do (it looked serious and skulls have been the first things that people used to put inside such shrines <a href="http://www.bernardinai.lt/straipsnis/2014-03-06-zivile-valiusaityte-keli-pastebejimai-ir-nusistebejmai-grozintis-lietuviskaja-kryzdirbyste/114804/print">back in the prehistoric period</a>).</p>
<p><img src="/assets/images/2014-11-22-goat_skull.jpg" alt="Goat" /></p>
<p>The right shrine housed a battery powered <a href="https://en.wikipedia.org/wiki/Maneki-neko">beckoning cat</a>, symbolising the shift of wealth and manufacturing to Asia:</p>
<p><img src="/assets/images/2014-11-22-cat.jpg" alt="Cat" /></p>
<p>Finally, we put a ceramic figurine of two kissing women with an overhanging red apple to the left one, symbolising the erasure of predetermined, absolute morality norms and the concept of sin. The apple was supposed to dry out without anyone biting it.</p>
<p><img src="/assets/images/2014-11-22-ladies.jpg" alt="Ladies" /></p>
<p>There were several other artifacts inside the small compartments of the shrine: a small <a href="http://www.instructables.com/id/cool-DIY-infinite-LED-tunnel/">infinity mirror</a>, a dried cheese, a small bottle of vodka, a tiny version of the silicone meadow, a 3D-printed <a href="https://en.wikipedia.org/wiki/Gediminas%27_Tower">Gediminas’ Tower</a>. I used <a href="https://3dwarehouse.sketchup.com/model.html?id=cd1d90f53cf9b6f5c2cb0e2631ee38c8">this model</a> as the basis for the printed one.</p>
<p><img src="http://41.media.tumblr.com/5da404e7979b9b4efa6420ccf5966523/tumblr_nakhrfhNTC1smrk23o4_500.jpg" alt="Castle" /></p>
<p>I was quite happy with this project in the end – after all, learning the basics of 3D design subsequently proved to be useful. Also, I always liked <a href="http://www.ldm.lt/naujausiosparodos/M_K_Ciurlionio34p.htm">this painting</a>.</p>
<p><img src="/assets/images/2014-11-22-fog.jpg" alt="Dusk" /></p>
<p>The end of this story was funny. A nice semi-naked Asian lady had become enfatuated with the shrine. Surely, we were happy to give it it to her. Here’s <em>miceuz</em> carrying the load to her camp:</p>
<p><img src="/assets/images/2014-11-22-mic_carries_the_load.jpg" alt="The load" />
(picture by R. Požerskis)</p>
<p>Unfortunately, the lady in question apparently was too spaced out to arrange transportation to the city she lived. Eventually we had to bring it back, cram it into our shipping container and leave it up to the folks who will go to the Burning Man the next year to decide what they’ll want to do with it.</p>
Electronic pregnancy test teardownopit2014-11-05T00:00:00+02:00https://wemakethings.net/2014/11/05/pregnancy_test<p>I had an opportunity to take a good look at the innards of a (used, negative) electronic pregnancy test.</p>
<p>A new, pristine test looks like that:</p>
<p><img src="http://cdn.clearblue.com/sites/default/files/cb9_main_02.png" alt="Electronic pregnancy test" /></p>
<p>Later one is supposed to piss on the probe (urine is unhealthily clear in this picture) or stick it into a small container with an urine sample:</p>
<p><img src="http://cdn.clearblue.com/sites/default/files/cb9_main_03.png" alt="Electronic pregnancy test" /></p>
<p>One’d see the result in the tiny LCD screen in 20 seconds or so.</p>
<p><img src="http://cdn.clearblue.com/sites/default/files/cb9_main_04.png" alt="Electronic pregnancy test" /></p>
<p>The case could be opened easily. I sticked a coin into its rear and turned. Spilled a couple of tiny Vinnic L736 1.5 V batteries:</p>
<p><img src="/assets/images/2014-11-05-easyblue_open.jpg" alt="Opening the case" /></p>
<p>The top view. The LCD screen, moisture absorbing material (the brownish pill), the back of the PCB.</p>
<p><img src="/assets/images/2014-11-05-easyblue_top.jpg" alt="Top view" /></p>
<p>The PCB – the tiny LCD screen is at the bottom. The microcontroller is coated in some black glop, and obviously everything in this area is patented and closed-source. The probe side is at the left. Basically, when the probe gets wet, the circuit closes and the test starts. It is a so-called <a href="https://en.wikipedia.org/wiki/Lateral_flow_test">lateral flow test</a>, <a href="http://uk.clearblue.com/healthcare-professionals/pregnancy-tests">presumably detecting</a> and measuring the concentration of the human chorionic gonadotrophin hormone that is initially produced by the embryo.</p>
<p>The stripes you can see in standard, analogue pregnancy tests and in the fourth picture are areas of the sporous pads where the target molecules and their antibodies that had been bound in the porous material accumulate. I think there are two control stripes on each of the two pads, and the test stripe that turns blue if a person is pregnant. This test should show the stage of early pregnancy too, apparently by estimating the concentration of HCG.</p>
<p><img src="/assets/images/2014-11-05-easyblue_pcb1.jpg" alt="Bottom view" /></p>
<p>I’m not sure about the exact method of test result analysis, but there are 4 diodes that would be directly underneath the 4 stripes on the pads, and a tiny CCD camera between them (maybe with another diode, marked D5 on the PCB). I think that the test works by detecting the change in LED light absorption with the CCD.</p>
<p>I’ll keep the LCD screen and the case. Might be fun to find another microcontroller, write something about a hybrid mechatronic baby and leave it somewhere.</p>
<p>Also, <a href="https://en.wikipedia.org/wiki/Pregnancy_test#History">here’s some history</a> of the middle XX century pregnancy tests: doctors would inject infantile female mice/rabbits with the urine of the subject, and then would dissect the animals, checking for presence of ovulation. Later on <a href="http://conservationmagazine.org/2013/09/old-pregnancy-test-frog-fungus/">frogs</a>, which did not need to be dissected and could have been kept alive, were used.</p>
Reverse engineering custom HP instrument keyboard protocolmiceuzioch2014-10-14T00:00:00+03:00https://wemakethings.net/2014/10/14/hp_kbd<p><img src="/assets/images/2014-10-21-hp-kb.jpg" alt="Mystery keyboard" /></p>
<p><em>ioch</em> had a go at disassembling a Gas Chromatographer with Flame Ionisation Detector made by HP in its glorious days - date codes on chips go back to 1975.
Except misc PCBs with gold-plated tracks it contained various interesting bits and pieces of hardware, including this
reed switch based keyboard.</p>
<p>Somehow we have decided to spend a Sunday poking at it.</p>
<p>The keyboard has a couple of SN74161 binary counters, SN74151 8-Line To 1-Line Data Selector and a SN74155 demultiplexer on it.</p>
<p><img src="/assets/images/2014-10-21-hp-kb-input.jpg" alt="Input interface" /></p>
<p>We didn’t care too much about internal workings of the thing, rather concentrated on what’s available on the
connector:</p>
<ul>
<li>CLK of SN74161 counter</li>
<li>LOAD, ENT, ENP of SN74161 counter tied together</li>
<li>QA of SN74161 counter</li>
<li>W of SN74151 data selector</li>
<li>D6 and D7 inputs of SN74151 multiplexer</li>
<li>2Y3 output of SN74155</li>
</ul>
<p>So, how would you read the keyboard with the interface provided? We would pull LOAD/ENT/ENP line high to reset/enable the counter,
then provide clock for it and hope the W output of the multiplexer will go high at some point if a key is pressed.
Different number of clocks before W goes high would correspond to a different key being pressed. Needless to say we were right.
The keyboard really was pulling W high after receiving some clock pulses, depenging on the key being pressed. The only problem was that it
was acting in a way we’ve called “a statistical keyboard” - the number of clocks would jump around a couple of values randomly, but at least those values were different for different keys pressed.</p>
<p>So we experimented more and discovered that pulling D6 and D7 high makes the number of clocks to stay constant and even key “0” correcponds to 0 clocks, “1” to 1 clock etc.</p>
<p>Also we’ve traced another board to which the keyboard connects and discovered that D6, D7 lines go thru a couple of fancy looking
reed relays which route them back to 12 pin of SN74155 - 2Y3 output. We’ve tried imitating those relays by shorting D6 D7 to 12 pin, the result
was that keyboard would be stuck to some defined value not reacting to key presses. Weird. Why would they have a couple of shmick relays on a separate board to do that?</p>
<p>Anyway, so much for the keys. In addition there are 8 LEDs on the keyboard that are connected to some custom HP chip with 515 marking on it.
We guessed it was some kind of shift register and were right at the second try.</p>
<p>Maybe we will use this keyboard as UI for one of our electric kilns.</p>
<p>Here goes the Arduino code from the experiment:</p>
<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="cp">#define CLK 6
#define LOAD 7
#define W 4
#define D6 9
#define D7 10
</span>
<span class="cp">#define LED_CLK 8
#define LED_DATA 5
</span>
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">9600</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">CLK</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">LOAD</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">D6</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">D7</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">W</span><span class="p">,</span> <span class="n">INPUT</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">LED_CLK</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">LED_DATA</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">W</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">D6</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">D7</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">LOAD</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">bangLeds</span><span class="p">(</span><span class="n">byte</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
<span class="n">byte</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">for</span><span class="p">(</span><span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o"><</span> <span class="mi">8</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">LED_DATA</span><span class="p">,</span> <span class="p">(</span><span class="o">~</span><span class="n">value</span> <span class="o">>></span> <span class="n">j</span><span class="p">)</span> <span class="o">&</span> <span class="mh">0x01</span><span class="p">);</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">LED_CLK</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">LED_CLK</span><span class="p">,</span> <span class="n">LOW</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">byte</span> <span class="n">keyCode</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">byte</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">loop2</span><span class="p">()</span> <span class="p">{</span>
<span class="n">bangLeds</span><span class="p">(</span><span class="n">j</span><span class="p">);</span>
<span class="n">j</span> <span class="o">=</span> <span class="n">j</span> <span class="o"><<</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="mi">0</span> <span class="o">==</span> <span class="n">j</span><span class="p">)</span> <span class="p">{</span>
<span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">CLK</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">CLK</span><span class="p">,</span> <span class="n">LOW</span><span class="p">);</span>
<span class="k">if</span><span class="p">(</span><span class="n">HIGH</span> <span class="o">==</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">W</span><span class="p">)){</span>
<span class="n">keyCode</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">keyCode</span><span class="p">);</span>
<span class="n">bangLeds</span><span class="p">(</span><span class="n">keyCode</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">i</span><span class="o">++</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="n">i</span> <span class="o">></span> <span class="mi">63</span><span class="p">)</span> <span class="p">{</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">LOAD</span><span class="p">,</span> <span class="n">LOW</span><span class="p">);</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">LOAD</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
<span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
Ural: reading analog video using a digital oscilloscopenightshade2014-10-12T00:00:00+03:00https://wemakethings.net/2014/10/12/ural-screenshot<p>I have an old russian Sinclair Spectrum clone called Урал 8/64K (Ural 8/64K).
It used to cost 998 roubles at the time of its release, in 1991. It has a Z80
CPU, 48KB of RAM and 16KB ROM containing a BASIC interpreter.</p>
<p>Similar to the original Spectrum, it connects to a TV for video and
audio output and to a magnetic casette recorder for saving and loading
user programs. But there is a slight difference: it has RGB and video
sync (RGBs) outputs, instead of the more usual composite or RF modulated
video. The hardware manual contains schematics that describe a way to
modify a “third-generation” russian TV to accept the input.</p>
<p><img src="/assets/images/2014-10-12-ural-tv-mod.jpg" alt="TV modification" /></p>
<p>The computer was given to me as a birthday gift at a very young age. I
was never able to use it because I didn’t have a modified TV, but I read
the manuals thoroughly, learned its BASIC dialect and imagined the
programs I could write. Recently I dug it out of the closet determined
to make it work.</p>
<p>First I tried to replace the DIN-7 connector on the TV cable with a
SCART connector (which can carry RGBs), and connect it to a TV. That
didn’t work, probably because I got the DIN pinout wrong.</p>
<p>Then I asked <em>ioch</em> to use his Rigol DS1052E oscilloscope to look at the
signals, hoping to understand them better.</p>
<p><img src="/assets/images/2014-10-12-ural-setup.jpg" alt="The setup" /></p>
<p>I connected the probe to what I think is the Y (grayscale) signal. The
video is scanned at about 15.63 kHz per line, 50 Hz per frame. It is
possible to trigger the scope on frame start by setting the trigger mode
to pulse width greater than about 0.1 ms. Then each line of video is
separated by shorter pulses with the pixel values between them. This can
be seen in the following graph, containing the start of a frame and some
pixels:</p>
<p><img src="/assets/images/2014-10-12-ural-graph.png" alt="Graph" /></p>
<p>The data from this graph was obtained using the oscilloscope’s USB
interface with Python and python-usbtmc. With some further processing
an image can be formed:</p>
<p><img src="/assets/images/2014-10-12-ural-screen.jpg" alt="Screenshot" /></p>
<p>I managed to make the frame processing to be done in real time at the
speed of about one frame per second, which was interesting for some
exploration, but not usable enough. The next thing I’ll try is fixing
the SCART interface.</p>
Burning Man tripopitvarious artists2014-09-07T00:00:00+03:00https://wemakethings.net/2014/09/07/burningman<p><a href="http://wemakethings.net/2013/10/03/summer-sauna/">This summer</a> we did something irrational and went to the <a href="http://burningman.org">Burning Man</a> with the <a href="http://wemakethings.net/2014/06/23/pieva">Silicone Meadow</a> installation. Here are some random pictures from the trip as I’m stuck at an airport.</p>
<p>We had a few days off, so we went to see the Pacific Ocean.</p>
<p><img src="/assets/images/2014-09-07-pacific.jpg" alt="Ocean" /></p>
<p>We landed at the desert and it was pretty empty – all the shelter we had was a shipping containter.</p>
<p><img src="/assets/images/2014-09-07-container.jpg" alt="Container" /></p>
<p>The spot in the desert for our installation</p>
<p><img src="/assets/images/2014-09-07-meadow_start.jpg" alt="Meadow on" /></p>
<p>We started to assemble the meadow at dusk</p>
<p><img src="/assets/images/2014-09-07-meadow-assembly.jpg" alt="Assembly" /></p>
<p>Laying the platform on the playa</p>
<p><img src="/assets/images/2014-09-07-meadow-playa.jpg" alt="playa" /></p>
<p>We turned it on..and everything worked until the elements took over.</p>
<p><img src="/assets/images/2014-09-07-meadow-on.jpg" alt="meadow on" /></p>
<p>We managed to save it from the rain which should not have happened, but after a couple of sandstorms the LEDs were buried deep in sand.</p>
<p><img src="/assets/images/2014-09-07-meadow-sand.jpg" alt="Sand" /></p>
<p>After the festival we dug the installation out, picked away all the raver detritus and left the sand as it was.</p>
<p><img src="/assets/images/2014-09-07-meadow-end.jpg" alt="Meadow-LNT" /></p>
<p>All in all, there were many beautiful things at the Burning Man</p>
<p><img src="/assets/images/2014-09-07-bm-tower.jpg" alt="Tower" /></p>
<p><img src="/assets/images/2014-09-07-candies.jpg" alt="Fireworks" /></p>
<p>We even got to fly over the city in a small airplane</p>
<p><img src="/assets/images/2014-09-07-brc-flight.jpg" alt="Plane" /></p>
<p>The real burning man – <em>Kipras</em> now has an atomic mushroom-shaped burn scar on his leg from this barrel.</p>
<p><img src="/assets/images/2014-09-07-padre-barrell.jpg" alt="burning man" /></p>
<p>The best times were had out of the desert, though. Chilling with the friendly raggamuffins (drįskiai) of East Oakland.</p>
<p><img src="/assets/images/2014-09-07-oakland-raggamuffins.jpg" alt="Oakland" /></p>
<p>The view from Twin Peaks in San Francisco:</p>
<p><img src="/assets/images/2014-09-07-twin-peaks.jpg" alt="on" /></p>
<p>Brooklyn Bridge in New York:</p>
<p><img src="/assets/images/2014-09-07-brooklyn-bridge.jpg" alt="on" /></p>
Enamelingopitauguste2014-08-08T00:00:00+03:00https://wemakethings.net/2014/08/08/enameling<p><em>Augustė</em> has been using her ceramics kiln here for enameling and metal casting.</p>
<p>The enamel powder
<img src="/assets/images/2014-08-08-enamels.jpg" alt="The enamels themselves" /></p>
<p>Cleaning the oxides from the test copper plates before enameling</p>
<p><img src="/assets/images/2014-08-08-cleaning1.jpg" alt="Cleaning1" /></p>
<p>She used water and citric acid solution for cleaning.</p>
<p><img src="/assets/images/2014-08-08-cleaning2.jpg" alt="Cleaning2" /></p>
<p>Fired samples of the colours</p>
<p><img src="/assets/images/2014-08-08-fired_tests.jpg" alt="Fired tests" /></p>
<p><img src="/assets/images/2014-08-08-fired_tests1.jpg" alt="Fired tests" /></p>
<p>She’s using marked copper test plates to see how different enamels look under different firing conditions
<img src="/assets/images/2014-08-08-marked_tests.jpg" alt="Marked" /></p>
<p>Melting paraffin wax for casting a copper pendant. First she made a positive cast from clay, then casted its imprint in silicone.</p>
<p><img src="/assets/images/2014-08-08-paraffin.jpg" alt="Paraffin" /></p>
<p>Then <em>Augustė</em> makes another positive cast in the wax mould from paraffin wax.</p>
<p><img src="/assets/images/2014-08-08-casting_mould.jpg" alt="Casting" /></p>
<p>Here’s the silicone mould filled with liquid wax. All is set for casting the metal!</p>
<p><img src="/assets/images/2014-08-08-casting_silicone.jpg" alt="Casting1" /></p>
Miner waste heat recyclingrxdtxd2014-08-03T00:00:00+03:00https://wemakethings.net/2014/08/03/miner-waste-heat-recycling<p>I’ve written before about <em>veox</em>’s <a href="/2013/10/12/miner_in_a_fridge_and_radeon_5850_disassembly/">cryptocurrency miner</a>. A common question with these beasts is <a href="http://www.reddit.com/r/litecoinmining/comments/265ar7/so_has_anyone_tried_doing_creative_things_with/">what the hell do we do</a> with all the waste heat. The answers we’ve come up with are:</p>
<ul>
<li>heating (sure thing, Sherlock);</li>
<li>drying food.</li>
</ul>
<p>So…</p>
<p><img src="/assets/images/2014-08-03-tomatoes.jpg" alt="Tomatoes on a dryer shelf in the mining fridge" /></p>
<p>We chose tomatoes for our first run, since:</p>
<ul>
<li>we all like them;</li>
<li>yield season;</li>
<li>if it can dry tomatoes, it can dry anything.</li>
</ul>
<p>If this works, we’ll try beef next, and (maybe) fish afterwards.</p>
<p><strong>UPDATE:</strong></p>
<p>After three days:</p>
<p><img src="/assets/images/2014-08-05-tomatoes2.jpg" alt="Semi-dried tomatoes after three days" /></p>
<p>A little mushy on first bite. The specific dried tomato taste kicks in after chewing for a few seconds.</p>
How to hack a manual control into a cheap DMX dimmermiceuzrxdtxd2014-07-23T00:00:00+03:00https://wemakethings.net/2014/07/23/dmx-pots<p><img src="/assets/images/2014-07-14-dmx-pots.jpg" alt="DMX pots" /></p>
<p>One of our friends wanted to have a manual-control LED dimmer for his stop motion setup. We had several of these cheap Chinese DMX dimmers. How does one adds potentiometer control to something like this? Just cut a trace from the RS485 transceiver into the unmarked micro, add another micro to act as a DMX master, and patch into the serial line via a SPDT switch.</p>
<p><img src="/assets/images/2014-07-14-dmx-internals.jpg" alt="DMX pots" /></p>
<p>The hacked-in micro just reads three potentiometers via ADC and spits their values into the DMX bus. We’ve found some DMX master code online and copied some stuffs into it:</p>
<script src="https://gist.github.com/Miceuz/1a32355f077c8457fef7.js"></script>
Silicone meadow - an interactive light installationmiceuzpwfievadinamakiprasursusopitgokuvarious artists2014-06-23T00:00:00+03:00https://wemakethings.net/2014/06/23/pieva<p><img src="/assets/images/2014-06-23-pieva-top.jpg" alt="Pieva - Silicone meadow" /></p>
<p>Once <em>Ieva</em> had a dream. She dreamt of a white meadow. Then she started researching materials and discovered silicone - it’s surprisingly robust, can handle wear and tear and the light cast on it gets diffused smoothly, creating a somewhat alien effect. We talked a bit about light source options, settled on addressable RGB LEDs as this made wiring and controlling them simple and forgot about this idea completely until a couple of months later the <a href="http://burningman.org">Burning Man</a> festival responded that they would accept and support the installation this year. Wow. Here we go.</p>
<p>Now we need your help to bring this thing to USA, please donate! Also, you can have a piece of the meadow for yourself!</p>
<center>
<iframe src="https://www.indiegogo.com/project/silicone-meadow/embedded" width="222px" height="445px" frameborder="0" scrolling="no"></iframe>
</center>
<p>How does one attaches a silicone hose to plywood? You can’t really cut the hose lengthwise and nail it down as this makes it vulnerable to tear, so we needed some kind of a custom holder. We considered brass tube fittings, but those are expensive and heavy. <em>pwf</em> quickly came up with this dumb and dirty prototype.</p>
<p><img src="/assets/images/2014-06-23-pieva-holder-proto.jpg" alt="The first custom holder prototype" /></p>
<p>It was clear that the work required to make 1k of these (we have settled on ~1k LEDs/tubes/pixels in total) will be boring as hell, so <em>pwf</em> made a bold decision and bought a 3D printer. He has made several design iterations until we settled on this final design.</p>
<p><img src="/assets/images/2014-06-23-pieva-holder-final.jpg" alt="The final holder design" /></p>
<p>It has a conical shape that in combination with the reflective spray-paint directs LED light into the tube, a channel to clip the wire and even some place for 0603 capacitor that is on the LED board. Well, printing 1k of those was a hell of a ride, but now we have some ideas about how to make large-scale 3D-printing a bit more feasible.</p>
<p><img src="/assets/images/2014-06-23-pieva-holder-perspective.jpg" alt="Half of them" /></p>
<p>at the end we called them “mushrooms”</p>
<p>The whole meadow is composed of 16 sections (now we have 9, but we will get there). The sections are made of plywood with holes for the hoses drilled and carefully routed.</p>
<p><img src="/assets/images/2014-06-23-pieva-sections.jpg" alt="Sections" /></p>
<p>Each section has a cutout on every side for easy cabling. Each cutout has a cover. <em>dinama</em>, <em>ursus</em> and <em>Kipras</em> have made these and attached a lot of “mushrooms”, each with two screws, while <em>Ieva</em> and <em>goku</em> cut, stripped and tinned wires and soldered 1k of LEDs, 6 connections each.</p>
<p><img src="/assets/images/2014-06-23-pieva-leds.jpg" alt="Lots of leds" /></p>
<p>We’ve considered connecting segments with short UTP patch-cables, but that would require expensive connectors we couldn’t afford. Instead we decided to wire point-to-point from the central pannel. UTP cable is abundant and cheap, we didn’t even had to buy it - <em>veox</em> still had a bundle that probably came from some forgotten shelf in my former office. The sections have these bottom-of-the-foodchain wall mountable cheap-ass RJ45 sockets. Some better than anothers.</p>
<p><img src="/assets/images/2014-06-23-pieva-utp.jpg" alt="RJ45" /></p>
<p>Anyway, signal after the socket looked ok-ish. Then I run a single twisted pair to the first LED and it got worse there. In the picture below the left trace is the signal after RJ45 box, the right - signal at the first LED. Pretty high overshoot, but no ringing. Probably playing around with terminator resistor values could help, or the edge could be slowed down a bit, but I had no time to play with this yet.</p>
<p><img src="/assets/images/2014-06-23-pieva-signal.jpg" alt="Signal after section connector" /></p>
<p>I’m happy with the idea of using a patch panel as a base for control electronics though.</p>
<p><img src="/assets/images/2014-06-23-pieva-controll.jpg" alt="Centrall controll" /></p>
<p>While researching the subject of controlling WS2812B LEDs I stumbled on <a href="http://www.misc.name/fadecandy/">Fadecandy</a> - it’s a module with a quite capable microcontroller that is solely preocuppied with driving those LEDs via buffered and terminated output, achieving high color dynamic range. And it’s open source. You have to be crazy not to use it for any kind of project with WS2812B. Fadecandies accept data via USB. That had set the whole stack for the project - Fadecandy, Raspberry Pi, Linux, Python, some C. However, I’m standing on the shoulders of giants here - the author of Fadecandy, <a href="http://www.misc.name">Micah</a>, had wrote almost everything you need to do a LED installation.</p>
<p>We’ve used a multi-stranded UTP cable wire and IDC connectors to connect candies to the patch pannel.</p>
<p><img src="/assets/images/2014-06-23-pieva-fadecandy.jpg" alt="Fadecandy" /></p>
<p>Here you can see part of the crew assembling the meadow for a live test.</p>
<p><img src="/assets/images/2014-06-23-pieva-assembly.jpg" alt="Pieva assembly" /></p>
<p>The code for our meadow is here: <a href="https://github.com/Technariumas/pieva">https://github.com/Technariumas/pieva</a>. I’m running a couple of layers <a href="Perlin noise">https://en.wikipedia.org/wiki/Perlin_noise</a> on the pixels. Initially I’ve tried to imitate a windy meadow with the sun shining on it (imagine the Windows XP wallpaper), but in the end we settled for a trippy palette selected by <em>opit</em>. I’ve tried to work out a reusable way of mapping LEDs to pixels, but eventually this turned out to be kludgy anyway. For each different section I’m importing a path that connects all LEDs from a SVG file and noting relative distances between LEDs, then I put sections together specifying the coordinates of the first pixel for each section.</p>
<p><img src="/assets/images/2014-06-23-pieva-fine-tuning.jpg" alt="Drunk fine-tuning" /></p>
<p>People have accepted the meadow surprisingly well. Kids instantly knew you can walk on it and the sight of elegant 50 year old women taking selfies while lying in the meadow - priceless!</p>
<p><img src="/assets/images/2014-06-23-pieva-live.jpg" alt="Pieva live" /></p>
<p><img src="/assets/images/2014-06-23-pieva-live1.jpg" alt="Pieva live" /></p>
<p><img src="/assets/images/2014-06-23-pieva-live2.jpg" alt="Pieva live" /></p>
<iframe width="640" height="360" src="//www.youtube.com/embed/uwLDYM3TAb4" frameborder="0" allowfullscreen="1"></iframe>
<p>Pictures and video by Urtė Sabutytė, also by <em>pwf</em> and Donis.</p>
Rotary encoder teardown (LPA3806-600BM-G5-24C)miceuz2014-05-26T00:00:00+03:00https://wemakethings.net/2014/05/26/rotary-encoder-teardown<p><img src="/assets/images/2014-05-16-encoder-LPA3806-600BM-G5-24C.jpg" alt="LPA3806-600BM-G5-24C" /></p>
<p>Recently we’ve purchased a couple of these cheap chinese rotary quadrature encoders with markings LPA3806-600BM-G5-24C on them. I’ve went and looked inside of one of them as documentation available online is rather scarce.</p>
<p><img src="/assets/images/2014-05-16-encoder-construction.jpg" alt="LPA3806-600BM-G5-24C construction" /></p>
<p>There’s not much to it - just what you would expect - a quadrature disc, and a LED/phototransistor module.</p>
<p><img src="/assets/images/2014-05-16-encoder-pcb.jpg" alt="LPA3806-600BM-G5-24C pcb" /></p>
<p>I’ve traced the schematics:</p>
<p><img src="/assets/images/2014-05-16-encoder-schematics.jpg" alt="LPA3806-600BM-G5-24C pcb" /></p>
<p>The circuit draws around 30mA. Outputs are open collector with 20 Ohm resistors for protection. Nice to see that they have added a “fools diode” D1 that will short out your power suply if you switch GND and VCC connections.</p>
<p>One thing to note - the encoder has a 5V linear regulator inside, so you want to power it with at least 7V power supply. Make sure the power dissipation in the internal regulator is within reasonable limits. The heat management is not spectacular in the encoder - case is connected to the chasis ground, not circuit ground and the internal LM7805 regulator in D-PAK packege relies on a big ground plane to act as a heatsink.</p>
<p>Let’s say we are powering it off 12V supply. The regulator has to dissipate (12V-5V) * 0.030A = 0.210W. Considering the worst case scenarion of RthJA beeing 100°C/W it would experience 21°C rise of junction temperature above the ambient. Considering the ambient to be 85°C we get the junction temperature to be at 106°C which is a bit too close to the absolute maximum of 125°C for my taste. As it’s a chinese noname product, I’d aim for the junction temperature not higher than 100°C. YMMV</p>
The TRIAC Bloc running a single phase AC motormiceuz2014-05-18T00:00:00+03:00https://wemakethings.net/2014/05/18/triac-bloc-motor-test<p>I’ve just made a small experiment to prove that <a href="http://wemakethings.net/2013/10/27/triac-bloc/">TRIAC Bloc</a> can control the speed of a single phase AC motor.</p>
<center><iframe width="420" height="315" src="//www.youtube.com/embed/f5Tr3FWEigQ" frameborder="0" allowfullscreen="yes">e</iframe></center>
jpgcompressveoxiochnightshade2014-05-10T00:00:00+03:00https://wemakethings.net/2014/05/10/jpgcompress<h2 id="intro">Intro</h2>
<p>This post started as an example session of writing for <a href="http://jekyllrb.com/">Jekyll</a> during a hack-and-tell afterparty. I was showing a simple shell script to compress JPEG images prior to publishing. We then decided to run it recursively. <em>veox</em> for keyboard jockey, <em>ioch</em> as an arbiter, <em>nightshade</em> for coding.</p>
<h2 id="result">Result</h2>
<video width="512" height="512" controls="controls">
<source src="https://cloud.technariumas.lt/index.php/s/6Bd4RN6POWUrPIW/download" type="video/mp4" /></source>
<source src="https://cloud.technariumas.lt/index.php/s/6zf2PWk5lrGNApY/download" type="video/ogg" /></source>
Your browser does not support the video tag.
</video>
<h2 id="process">Process</h2>
<p>We used a standard <a href="https://en.wikipedia.org/wiki/Lenna">lenna</a> image.</p>
<h3 id="jpgcompress">jpgcompress</h3>
<figure class="highlight"><pre><code class="language-sh" data-lang="sh"><span class="c">#!/bin/sh</span>
<span class="c"># TODO: run recursively</span>
<span class="nv">tmpfile</span><span class="o">=</span><span class="s2">"/tmp/jpegcompress.pnm"</span>
<span class="k">for </span>f <span class="k">in</span> <span class="nv">$1</span>; <span class="k">do
</span>djpeg <span class="nv">$f</span> > <span class="nv">$tmpfile</span>
cjpeg -quality <span class="nv">$2</span> <span class="nv">$tmpfile</span> > <span class="nv">$f</span>
<span class="k">done
</span>rm <span class="nv">$tmpfile</span></code></pre></figure>
<h3 id="compress-recursively">compress-recursively</h3>
<figure class="highlight"><pre><code class="language-sh" data-lang="sh"><span class="c">#!/bin/zsh</span>
<span class="nv">filename</span><span class="o">=</span>lenna.jpg
convert lenna.png <span class="nv">$filename</span>
<span class="k">for </span>i <span class="k">in</span> <span class="sb">`</span>seq 1 1000<span class="sb">`</span>; <span class="k">do
</span><span class="nb">echo</span> <span class="s2">"</span><span class="nv">$i</span><span class="s2">"</span>
cp <span class="nv">$filename</span> <span class="sb">`</span><span class="nb">printf</span> <span class="s2">"%06d.jpg"</span> <span class="nv">$i</span><span class="sb">`</span>
jpgcompress <span class="nv">$filename</span> <span class="k">$((</span><span class="o">(</span><span class="m">1000</span><span class="o">-</span>i<span class="o">)/</span><span class="m">10</span><span class="k">))</span>
<span class="k">done</span></code></pre></figure>
<p><strong>Note</strong>: quantization starts showing at iteration 761.</p>
<h3 id="intermediate-results">Intermediate results</h3>
<p><img src="/assets/images/2014-05-10-jpgcompress/000001.jpg" alt="begin" />
<img src="/assets/images/2014-05-10-jpgcompress/000500.jpg" alt="middle" />
<img src="/assets/images/2014-05-10-jpgcompress/000888.jpg" alt="nearend" />
<img src="/assets/images/2014-05-10-jpgcompress/000980.jpg" alt="end" /></p>
<h3 id="create-video-from-jpeg-images">Create video from jpeg images</h3>
<div class="highlighter-rouge"><pre class="highlight"><code>ffmpeg -i %06d.jpg -c:v libx264 -r 30 -pix_fmt yuv420p out.mp4
ffmpeg -i %06d.jpg -c:v theora -r 30 -pix_fmt yuv420p out.ogg
</code></pre>
</div>
A K-type thermocouple library for embedded applicationsmiceuz2014-04-24T00:00:00+03:00https://wemakethings.net/2014/04/24/k-thermocouple-lib<p>I was looking for a free K-type thermocouple linearization and cold
junction compensation code online and couldn’t find it, so I wrote one.
It’s on my <a href="https://github.com/Miceuz/k-thermocouple-lib/">github</a>.</p>
<p>There are some libraries available that use polynomial based
linearization, but those are not really suitable for embedded
applications as floating point operations and math functions take a lot
of program space. Besides, it’s possible to achieve the same or better
accuracy using a hand-picked lookup table with less code.</p>
<p>The idea is like this - pick up some points and interpolate the unknown
values linearly.
<img src="/assets/images/2014-04-24-principle.jpg" alt="" /></p>
<p>Points do not have to be distributed evenly. One can put more points in
more nonlinear parts of the response one is trying to approximate. I’ve
chosen 65 points and shuffled them around to get the minimal error. Data
was taken from K-thermocouple tables provided by
<a href="http://srdata.nist.gov/its90/main/its90_main_page.html">NIST</a>.</p>
<p><img src="/assets/images/2014-04-24-lookup-table-selection.png" alt="" /></p>
<p>I’ve used fixed point arithmetics for all the calculations. This makes
the library lightweight when compared to polynomial-based libraries that
use floating point operations.</p>
<p>On the plots below you can see a characterization of errors introduced
by the algorithm. The temperature conversion accuracy is typically less
than 0.06 degrees C for a K-type thermocouple. My library produces
slightly better results with less code.</p>
<p><img src="/assets/images/2014-04-24-error-temperature-vs-voltage.png" alt="" />
<img src="/assets/images/2014-04-24-error-temperature-vs-voltage-hist.png" alt="" /></p>
<p><img src="/assets/images/2014-04-24-error-voltage-vs-temperature.png" alt="" />
<img src="/assets/images/2014-04-24-error-voltage-vs-temperature-hist.png" alt="" /></p>
<p>The code currently does not support negative ambient temperatures, it’s
work in progress. I’m open for comments and questions. Ping me if you
find it useful.</p>
<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="cp">#define POINTS_COUNT 65
</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
<span class="kt">long</span> <span class="n">temp</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">microvolts</span><span class="p">;</span>
<span class="p">}</span> <span class="n">temp_point</span><span class="p">;</span>
<span class="k">static</span> <span class="n">temp_point</span> <span class="n">thermocouplePoints</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span>
<span class="p">{</span> <span class="mi">0</span> <span class="p">,</span> <span class="mi">0</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">10000</span> <span class="p">,</span> <span class="mi">397</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">20000</span> <span class="p">,</span> <span class="mi">798</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">30000</span> <span class="p">,</span> <span class="mi">1203</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">40000</span> <span class="p">,</span> <span class="mi">1612</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">50000</span> <span class="p">,</span> <span class="mi">2023</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">60000</span> <span class="p">,</span> <span class="mi">2436</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">79000</span> <span class="p">,</span> <span class="mi">3225</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">98000</span> <span class="p">,</span> <span class="mi">4013</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">116000</span> <span class="p">,</span> <span class="mi">4756</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">134000</span> <span class="p">,</span> <span class="mi">5491</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">139000</span> <span class="p">,</span> <span class="mi">5694</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">155000</span> <span class="p">,</span> <span class="mi">6339</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">172000</span> <span class="p">,</span> <span class="mi">7021</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">193000</span> <span class="p">,</span> <span class="mi">7859</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">212000</span> <span class="p">,</span> <span class="mi">8619</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">231000</span> <span class="p">,</span> <span class="mi">9383</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">250000</span> <span class="p">,</span> <span class="mi">10153</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">269000</span> <span class="p">,</span> <span class="mi">10930</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">288000</span> <span class="p">,</span> <span class="mi">11712</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">307000</span> <span class="p">,</span> <span class="mi">12499</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">326000</span> <span class="p">,</span> <span class="mi">13290</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">345000</span> <span class="p">,</span> <span class="mi">14084</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">364000</span> <span class="p">,</span> <span class="mi">14881</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">383000</span> <span class="p">,</span> <span class="mi">15680</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">402000</span> <span class="p">,</span> <span class="mi">16482</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">421000</span> <span class="p">,</span> <span class="mi">17285</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">440000</span> <span class="p">,</span> <span class="mi">18091</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">459000</span> <span class="p">,</span> <span class="mi">18898</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">478000</span> <span class="p">,</span> <span class="mi">19707</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">497000</span> <span class="p">,</span> <span class="mi">20516</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">516000</span> <span class="p">,</span> <span class="mi">21326</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">535000</span> <span class="p">,</span> <span class="mi">22137</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">554000</span> <span class="p">,</span> <span class="mi">22947</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">573000</span> <span class="p">,</span> <span class="mi">23757</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">592000</span> <span class="p">,</span> <span class="mi">24565</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">611000</span> <span class="p">,</span> <span class="mi">25373</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">630000</span> <span class="p">,</span> <span class="mi">26179</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">649000</span> <span class="p">,</span> <span class="mi">26983</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">668000</span> <span class="p">,</span> <span class="mi">27784</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">687000</span> <span class="p">,</span> <span class="mi">28584</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">706000</span> <span class="p">,</span> <span class="mi">29380</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">725000</span> <span class="p">,</span> <span class="mi">30174</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">744000</span> <span class="p">,</span> <span class="mi">30964</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">763000</span> <span class="p">,</span> <span class="mi">31752</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">782000</span> <span class="p">,</span> <span class="mi">32536</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">801000</span> <span class="p">,</span> <span class="mi">33316</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">820000</span> <span class="p">,</span> <span class="mi">34093</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">839000</span> <span class="p">,</span> <span class="mi">34867</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">858000</span> <span class="p">,</span> <span class="mi">35637</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">877000</span> <span class="p">,</span> <span class="mi">36403</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">896000</span> <span class="p">,</span> <span class="mi">37166</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">915000</span> <span class="p">,</span> <span class="mi">37925</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">934000</span> <span class="p">,</span> <span class="mi">38680</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">953000</span> <span class="p">,</span> <span class="mi">39432</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">972000</span> <span class="p">,</span> <span class="mi">40180</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">991000</span> <span class="p">,</span> <span class="mi">40924</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">1010000</span> <span class="p">,</span> <span class="mi">41665</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">1029000</span> <span class="p">,</span> <span class="mi">42402</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">1048000</span> <span class="p">,</span> <span class="mi">43134</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">1067000</span> <span class="p">,</span> <span class="mi">43863</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">1086000</span> <span class="p">,</span> <span class="mi">44588</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">1105000</span> <span class="p">,</span> <span class="mi">45308</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">1124000</span> <span class="p">,</span> <span class="mi">46024</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">1143000</span> <span class="p">,</span> <span class="mi">46735</span> <span class="p">},</span>
<span class="p">{</span> <span class="mi">1200000</span> <span class="p">,</span> <span class="mi">48838</span> <span class="p">}</span>
<span class="p">};</span>
<span class="k">static</span> <span class="kr">inline</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="nf">interpolate</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">val</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span>
<span class="n">rangeStart</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">rangeEnd</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">valStart</span><span class="p">,</span> <span class="kt">unsigned</span>
<span class="kt">long</span> <span class="n">valEnd</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">rangeStart</span> <span class="o">+</span> <span class="p">(</span><span class="n">rangeEnd</span> <span class="o">-</span> <span class="n">rangeStart</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="n">val</span> <span class="o">-</span> <span class="n">valStart</span><span class="p">)</span> <span class="o">/</span>
<span class="p">(</span><span class="n">valEnd</span> <span class="o">-</span> <span class="n">valStart</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">static</span> <span class="kr">inline</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">interpolateVoltage</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">temp</span><span class="p">,</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">i</span><span class="p">){</span>
<span class="k">return</span> <span class="n">interpolate</span><span class="p">(</span><span class="n">temp</span><span class="p">,</span> <span class="n">thermocouplePoints</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="n">microvolts</span><span class="p">,</span>
<span class="n">thermocouplePoints</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">microvolts</span><span class="p">,</span> <span class="n">thermocouplePoints</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="n">temp</span><span class="p">,</span>
<span class="n">thermocouplePoints</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">temp</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">static</span> <span class="kr">inline</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">interpolateTemperature</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span>
<span class="n">microvolts</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">i</span><span class="p">){</span>
<span class="k">return</span> <span class="n">interpolate</span><span class="p">(</span><span class="n">microvolts</span><span class="p">,</span> <span class="n">thermocouplePoints</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="n">temp</span><span class="p">,</span>
<span class="n">thermocouplePoints</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">temp</span><span class="p">,</span> <span class="n">thermocouplePoints</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="n">microvolts</span><span class="p">,</span>
<span class="n">thermocouplePoints</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">microvolts</span><span class="p">);</span>
<span class="p">}</span>
<span class="cm">/**
* Returns the index of the first point whose temperature value is
greater than the argument
**/</span>
<span class="k">static</span> <span class="kr">inline</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">searchTemp</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">temp</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">i</span><span class="p">;</span>
<span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">POINTS_COUNT</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="n">thermocouplePoints</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">temp</span> <span class="o">></span> <span class="n">temp</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">i</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">POINTS_COUNT</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="cm">/**
* Returns the index of the first point whose microvolts value is
greater than the argument
**/</span>
<span class="k">static</span> <span class="kr">inline</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">searchMicrovolts</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">microvolts</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">i</span><span class="p">;</span>
<span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">POINTS_COUNT</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="n">thermocouplePoints</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">microvolts</span> <span class="o">></span> <span class="n">microvolts</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">i</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">POINTS_COUNT</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="cm">/**
* Returns temperature as a function of the ambient temperature and the
measured thermocouple voltage.
* Currently only positive ambient temperature is supported
**/</span>
<span class="kt">long</span> <span class="n">thermocoupleConvertWithCJCompensation</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span>
<span class="n">microvoltsMeasured</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">ambient</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">//convert ambient temp to microvolts
</span> <span class="c1">//and add them to the thermocouple measured microvolts
</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">microvolts</span> <span class="o">=</span> <span class="n">microvoltsMeasured</span> <span class="o">+</span>
<span class="n">interpolateVoltage</span><span class="p">(</span><span class="n">ambient</span><span class="p">,</span> <span class="n">searchTemp</span><span class="p">(</span><span class="n">ambient</span><span class="p">));</span>
<span class="c1">//look up microvolts in The Table and interpolate
</span> <span class="k">return</span> <span class="n">interpolateTemperature</span><span class="p">(</span><span class="n">microvolts</span><span class="p">,</span> <span class="n">searchMicrovolts</span><span class="p">(</span><span class="n">microvolts</span><span class="p">));</span>
<span class="p">}</span></code></pre></figure>
Modifying a Konica C35 to use modern batteriesnightshade2014-02-04T00:00:00+02:00https://wemakethings.net/2014/02/04/konica-c35-modern-batteries<p>Konica C35 is a 35mm compact rangefinder film camera released in 1968.
It has a CdS photoresistor based light meter which controls shutter
speed and aperture. To power the meter the camera takes a single
PX675/MR44 1.35V mercury cell, which was common at the time. The camera
uses miniscule amounts of current, no more than 1mA, and only when the
lens-cap is off, so the batteries could last years. The problem is that
this kind of battery is banned due to environmental concerns about its
mercury content.</p>
<p><img src="/assets/images/2014-02-04-konica-c35-fed-mikron-2-small.jpg" alt="Konica C35 and FED Mikron 2" /></p>
<p>The FED Mikron 2 shown in this picture is C35’s slightly bigger and
bulkier ukrainian brother. Its meter works the same way and it has the
same battery problem, as do many other cameras of that time.</p>
<p>The metering circuit is very simple. A voltmeter is connected in series
with the photoresistor and battery.</p>
<p><img src="/assets/images/2014-02-04-konica-schematic.png" alt="Meter schematic" /></p>
<p>The camera also has a film speed (ISO) setting, controlled by a ring around the
lens, which doesn’t have any corresponding element in the schematic. That is
because the ISO setting selects an aperture for the photoresistor (which is
directly above the lens), decreasing the amount of light that reaches it.</p>
<p><img src="/assets/images/2014-02-04-konica-lens.jpg" alt="Lens" /></p>
<p>The photoresistor’s resistance changes from basically an open circuit in
darkness to very low in bright light. The change is non-linear, but the
shutter mechanism takes that into account. The voltmeter’s needle is
visible in the camera’s viewfinder and is mechanically coupled to
control the shutter/aperture mechanism. In the picture below the needle
is at the very bottom of the scale because the camera is without a
battery.</p>
<p><img src="/assets/images/2014-02-04-konica-viewfinder.jpg" alt="Viewfinder" /></p>
<p>The accuracy of this system depends on a constant voltage source. The
PX675/MR44 battery has the same form factor like LR44 alkaline and SR44
silver-oxide baterries, but a voltage of 1.35V which stays basically
constant until the battery is almost completely discharged and then it
drops off sharply. This characteristic makes it suitable to be a
reference voltage.</p>
<p>Zinc-air A675 cells can be used as replacements because they have a
voltage of 1.35V too. They are usually sold as hearing-aid batteries.
But they have one drawback: short operating life. They use air for the
reaction and discharge in a few months even when they are not being
used, which is far from ideal.</p>
<p>On the other hand SR44 silver-oxide cells have similar discharge
characteristics and long shelf life of mercury batteries, but a
different voltage, 1.55V. This 0.2V difference can make the camera
overexpose by a few EV. This can be compensated by setting a lower ISO
on the meter, but that is not always accurate. A more accurate way is to
insert a 0.2V drop diode in series into the circuit.</p>
<p>Note that common alkaline LR44 cells are not suitable for this, because their
voltage decreases as they discharge.</p>
<p>Diode forward voltage drop depends on current and temperature. The
current dependency graph for various kinds of diodes is shown below. The
graph is taken from a very thorough <a href="http://www.butkus.org/chinon/batt-adapt-us.pdf">article about mercury battery
replacement on
butkus.org</a>.</p>
<p><img src="/assets/images/2014-02-04-konica-graph.png" alt="Diode graph" /></p>
<p>There is also a line for a 2k resistor in the graph. It is nonlinear
and steep around 1.35V, which is why a resistor is not suitable. This is
also the reason the ISO setting is implemented using apertures and not
resistors.</p>
<p>I chose to use a BAT43 Schottky diode, but the best choice depends on
the camera and how much current it uses. BAT43’s forward voltage drop
graph is shown below (taken from the datasheet).</p>
<p><img src="/assets/images/2014-02-04-konica-bat43-voltage.png" alt="BAT43 voltage graph" /></p>
<p>In a C35 the easiest place to insert the diode is near the battery
compartment. To access it unscrew the battery holder and three little
screws on the bottom plate, open the film door and remove the bottom
plate.</p>
<p><img src="/assets/images/2014-02-04-konica-build1.jpg" alt="Bottom plate" /></p>
<p>Unscrew the two screws holding the battery compartament. Desolder the
red wire.</p>
<p><img src="/assets/images/2014-02-04-konica-build2.jpg" alt="Battery compartment" /></p>
<p>Solder the diode between the terminal and the wire. Make sure sure the
polarity is correct (this is the positive terminal of the battery).</p>
<p><img src="/assets/images/2014-02-04-konica-build3.jpg" alt="Diode soldered" /></p>
<p>That’s it, the camera can now be used with a silver oxide battery. I
haven’t tested with film yet, but the meter seems to be working
properly.</p>
A DIY driver for EQ2 equatorial mount motormiceuz2013-12-31T00:00:00+02:00https://wemakethings.net/2013/12/31/eq1_drive<p><img src="/assets/images/2013-12-31-scope.png" alt="" /></p>
<p>We wanted to give a telescope as a Christmas present to one kid.
Luckily enough we have happened to find one standing under the autumn rain in a second hand junk yard in Berlin.
The telescope itself was dusty and wet, but the mount was in a good shape, just the driver electronics for the motor were missing.</p>
<p>After some poking and googling I was able to determine that the mount uses a bipolar stepper motor to compensate for Earth’s rotation. How do you drive a bipolar stepper? Well, you just hook up a couple of H-bridges and let the microcontroller switch them.</p>
<p>I didn’t have enought time to order parts, design and etch the PCB, etc, so I decided to use whatever I had around.
The code and schematics are available on my <a href="https://github.com/Miceuz/astromotor">github</a> repo if someone wants to reproduce this or just to poke around.</p>
<p><img src="/assets/images/2013-12-31-driver-board.png" alt="" /></p>
<p>Here you can see an H-bridge circuit built using BDW93/BDW94 Darlington transistors - those just happened to be laying in my junk box after
I had dissasembled some projector TV I had found on a street a year ago. It had lots of linear amplification - lots and lots of matched NPN/PNP power transistors. Probably Darlingtons are suboptimal in this application, mosfets would be better, but in the end the motor was turning and driving the whole telescope assembly at a reasonable power consumption so I guess it’s good enough.</p>
<p>I’ve tried to reproduce the functionality of the commercial EQ2 driver. When turned on, the driver starts to turn the motor at a constant rate of 1 revolution per 70 seconds. Buttons allow for double speed fast-forward and rewind. I decided to make do without a tumbler for changing a default direction of rotation, but add a potentiometer to fine-tune the rotation speed.</p>
<p>I want to thank the author of <a href="http://astrobling.weebly.com/drive-motor-speed-adjuster.html">this page</a> for providing valuable information about motor rotation speeds and gear ratios.</p>
<p><img src="/assets/images/2013-12-31-schematics.png" alt="" /></p>
<p>Since I ran out of all the SO to DIP adapters, I had to deadbug the ATTiny44 micro. Not my favorite style, but it went ok.</p>
<p><img src="/assets/images/2013-12-31-mcu.png" alt="" /></p>
<p>I had this LT1117 LDO board from an earlier project. The LDO was of the adjustable variety, so I hooked it up to source ~3.6V for a microcontroller.</p>
<p><img src="/assets/images/2013-12-31-ldo.png" alt="" /></p>
<p>The bottom of a veroboard never looks good, but in this case I’m pretty happy with it.</p>
<p><img src="/assets/images/2013-12-31-bottom.png" alt="" /></p>
<p>When cramming everything into a case I was repeating to myself: “I will never design a PCB without selecting a case first again, I will never design a PCB without selecting a case first again, I will never design a PCB without selecting a case first again, I will never design a PCB without selecting a case first again…”</p>
<p>The driver is powered by 6 AA batteries. Voltage for the motor is provided by an adjustable switching DC-DC converter based on LM2596 (a cheap Chinese module off ebay). On average it draws about 0.1A of current at 6.5V, this allows for some 8 - 12 hours of operation on one battery set.</p>
<p><img src="/assets/images/2013-12-31-intozebox.png" alt="" /></p>
<p>The final driver in an enclosure looks like this</p>
<p><img src="/assets/images/2013-12-31-zebox.png" alt="" /></p>
<p>The code is not spectacular - I have an array of H-bridge switching configurations and output them to MCU IO port on every timer compare match interrupt:</p>
<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="c1">//HIGH torque, high power stepping
</span><span class="kt">uint8_t</span> <span class="n">stepProfile2</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span>
<span class="mi">0</span><span class="n">b00000101</span><span class="p">,</span>
<span class="mi">0</span><span class="n">b00000110</span><span class="p">,</span>
<span class="mi">0</span><span class="n">b00001010</span><span class="p">,</span>
<span class="mi">0</span><span class="n">b00001001</span>
<span class="p">};</span>
<span class="n">ISR</span><span class="p">(</span><span class="n">TIM1_COMPB_vect</span><span class="p">)</span> <span class="p">{</span>
<span class="n">doStep</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">TCNT1</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">//...
</span> <span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="n">doStep</span><span class="p">)</span> <span class="p">{</span>
<span class="n">i</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="n">direction</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="n">DIR_CW</span> <span class="o">==</span> <span class="n">direction</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="n">i</span> <span class="o">></span> <span class="mi">3</span><span class="p">)</span> <span class="p">{</span>
<span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="n">i</span> <span class="o"><</span> <span class="mi">0</span><span class="p">){</span>
<span class="n">i</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">PORTA</span> <span class="o">&=</span> <span class="mi">0</span><span class="n">b11110000</span><span class="p">;</span>
<span class="n">PORTA</span> <span class="o">|=</span> <span class="n">stepProfile2</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
<span class="n">doStep</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">//...
</span><span class="p">}</span></code></pre></figure>
Evolutionary optimization of PID parameters for empirically identified systemmiceuz2013-12-01T00:00:00+02:00https://wemakethings.net/2013/12/01/pid_genetics<h1 id="introduction">Introduction</h1>
<p>If you have ever tried to control the temperature or the position of a motor using a microcontroller, you probably know that the task is not as trivial as it sounds. You can’t just keep the heater on until the desired temperature is reached. Because of the intrinsic inertia of the system the temperature will overshoot and a motor will stop too late.</p>
<p>To perform the task you have to resort to control theory - differential equations, Laplace trasforms, poles and zeros. Luckily, lots of very math savvy people have already done that and came up with a very simple and very successfull control scheme called a PID controller. In a nutshell, you have to choose only three parameters for proportional, integral and differential parts of the controller. Well, choosing the right parameters leads back to a mathematical modelling of the system or blind intuitive doodling of trial and error.</p>
<p>As it is, I wanted to try using a genetic algorithm for a long time, just didn’t find a good application for it in connection to the stuff I was doing, until one day it struck me - PID controller has three parameters - that makes three genes. What if I try to find an optimal configuration using a genetic approach?</p>
<h1 id="the-plant">The plant</h1>
<p><img src="/assets/images/2013-12-01_plant.jpg" alt="" /></p>
<p>In control theory, the system under control is called a “plant”. My plant consists of a microcontroller, a DS18B20 temperature sensor and a resistor as a heater. Microcontroller pulses current through the resistor by applying pulse width modulated signal to a base of a transistor - that is called control signal. Temperature that is measured by the sensor is called the output of the system.</p>
<h1 id="modelling">Modelling</h1>
<p>## Step response</p>
<p>Step response is a reaction of a system to the maximum signal level at its input. In my case this was PWM signal on a microcontroller. I chose my maximum to be 128 as it keeps the resistor from smoking and leaves the system a bit of hump behind it, if PID algorithm chooses to overdrive the control signal.</p>
<p><img src="/assets/images/2013-12-01_step_response.png" alt="" /></p>
<h2 id="impulse-response">Impulse response</h2>
<p>Impulse response is the derivative of the step response.</p>
<p><img src="/assets/images/2013-12-01_impulse_response.png" alt="" /></p>
<p>Impulse response is everything there is to be known about the system. It fully describes the possible behaviour of the system (provided some limitations - system has to be linear for this to work). To predict the behaviour of the system, for every discrete input value you have to multiply the impulse response by Dirac delta, scaled to input value, to get the ouput; and then on the next input, shift the previous output to right and add new output on the top, so impulse responses overlap on top of each other while time passes. This is called convolution.</p>
<p>Convolving impulse response with Dirac delta means applying full power to a system. Test the impulse response by convolving it with Dirac delta and compare it to our step response.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c">#convolve impuse reponse with 1. 1 * ir = y</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">idx</span><span class="p">(</span><span class="n">y</span><span class="p">):</span>
<span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="n">idx</span><span class="p">(</span><span class="n">ir</span><span class="p">):</span>
<span class="n">output</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">output</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">*</span> <span class="n">ir</span><span class="p">[</span><span class="n">j</span><span class="p">]</span></code></pre></figure>
<p><img src="/assets/images/2013-12-01_simulation.png" alt="" /></p>
<p>Nothing spectacular if you look at the math, but the result is really important, because now I can model my plant in software pretty accurately.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c">#this function processes one controll step at time t</span>
<span class="k">def</span> <span class="nf">processStep</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">scaling</span><span class="p">):</span>
<span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="n">idx</span><span class="p">(</span><span class="n">irFiltered</span><span class="p">):</span>
<span class="n">output</span><span class="p">[</span><span class="n">t</span><span class="o">+</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">output</span><span class="p">[</span><span class="n">t</span><span class="o">+</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="n">irFiltered</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">*</span> <span class="n">scaling</span></code></pre></figure>
<h2 id="pid-algorithm">PID algorithm</h2>
<p>For my PID controller I’ve just used the first hit on the web search when looking for “PID Python”. It’s a bog standard PID implementation without any bells or whistles.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span><span class="n">current_value</span><span class="p">):</span>
<span class="s">"""
Calculate PID output value for given reference input and feedback
"""</span>
<span class="bp">self</span><span class="o">.</span><span class="n">error</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">set_point</span> <span class="o">-</span> <span class="n">current_value</span>
<span class="bp">self</span><span class="o">.</span><span class="n">P_value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">Kp</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">error</span>
<span class="bp">self</span><span class="o">.</span><span class="n">D_value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">Kd</span> <span class="o">*</span> <span class="p">(</span> <span class="bp">self</span><span class="o">.</span><span class="n">Derivator</span> <span class="o">-</span> <span class="n">current_value</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">Derivator</span> <span class="o">=</span> <span class="n">current_value</span>
<span class="bp">self</span><span class="o">.</span><span class="n">Integrator</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">Integrator</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">error</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">Integrator</span> <span class="o">></span> <span class="bp">self</span><span class="o">.</span><span class="n">Integrator_max</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">Integrator</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">Integrator_max</span>
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">Integrator</span> <span class="o"><</span> <span class="bp">self</span><span class="o">.</span><span class="n">Integrator_min</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">Integrator</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">Integrator_min</span>
<span class="bp">self</span><span class="o">.</span><span class="n">I_value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">Integrator</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">Ki</span>
<span class="n">PID</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">P_value</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">I_value</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">D_value</span>
<span class="k">if</span> <span class="n">PID</span> <span class="o">></span> <span class="mi">1</span><span class="p">:</span>
<span class="n">PID</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="n">PID</span> <span class="o"><</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">PID</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">return</span> <span class="n">PID</span></code></pre></figure>
<h1 id="optimization">Optimization</h1>
<h2 id="error-measure">Error measure</h2>
<p>To find an optimal solution, we need to have a way to estimate the controller performance. I’ve tried three estimation approaches with slightly different results, the final one I’ve chosen is called Integral of Time Absolute Error - it penalizes error the more the later it occurs.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">evaluate</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">setpoint</span><span class="p">):</span>
<span class="k">global</span> <span class="n">output</span>
<span class="n">ITAE</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">MSE</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">IAE</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">output</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="mi">150</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">ir</span><span class="p">))</span>
<span class="n">controls</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="mi">150</span><span class="p">)</span>
<span class="n">p</span><span class="o">.</span><span class="n">setPoint</span><span class="p">(</span><span class="n">setpoint</span><span class="p">)</span>
<span class="n">control</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">150</span><span class="p">):</span>
<span class="n">controls</span><span class="p">[</span><span class="n">t</span><span class="p">]</span> <span class="o">=</span> <span class="n">control</span>
<span class="n">processStep</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">control</span><span class="p">)</span>
<span class="n">control</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">output</span><span class="p">[</span><span class="n">t</span><span class="p">])</span>
<span class="n">error</span> <span class="o">=</span> <span class="n">output</span><span class="p">[</span><span class="n">t</span><span class="p">]</span> <span class="o">-</span> <span class="n">setpoint</span>
<span class="n">ITAE</span> <span class="o">=</span> <span class="n">ITAE</span> <span class="o">+</span> <span class="n">t</span> <span class="o">*</span> <span class="nb">abs</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
<span class="n">MSE</span> <span class="o">=</span> <span class="n">MSE</span> <span class="o">+</span> <span class="n">error</span><span class="o">**</span><span class="mi">2</span>
<span class="n">IAE</span> <span class="o">=</span> <span class="n">IAE</span> <span class="o">+</span> <span class="nb">abs</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
<span class="n">output</span> <span class="o">=</span> <span class="n">output</span><span class="p">[:</span><span class="o">-</span><span class="nb">len</span><span class="p">(</span><span class="n">ir</span><span class="p">)]</span>
<span class="n">MSE</span> <span class="o">=</span> <span class="n">MSE</span> <span class="o">/</span> <span class="mi">150</span>
<span class="k">return</span> <span class="n">ITAE</span></code></pre></figure>
<h2 id="evolution">Evolution</h2>
<p>I start with a random population of PID controllers. On each evolution step a third of the population dies, then the best specimen mates with the better half of the remaining population and the rest mate and mutate randomly.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">nextGeneration</span><span class="p">(</span><span class="n">population</span><span class="p">):</span>
<span class="n">population</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">individual</span><span class="p">:</span> <span class="n">individual</span><span class="o">.</span><span class="n">getFitness</span><span class="p">())</span>
<span class="n">population</span> <span class="o">=</span> <span class="n">population</span><span class="p">[:</span><span class="o">-</span><span class="n">POPULATION</span><span class="o">/</span><span class="mi">3</span><span class="o">*</span><span class="mi">2</span><span class="p">]</span> <span class="c">#part of population dies</span>
<span class="n">alpha</span> <span class="o">=</span> <span class="n">population</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="c">#alpha female mates with the best without mutation</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">POPULATION</span><span class="o">/</span><span class="mi">3</span> <span class="o">-</span> <span class="mi">1</span><span class="p">):</span>
<span class="n">mama</span> <span class="o">=</span> <span class="n">alpha</span>
<span class="n">papa</span> <span class="o">=</span> <span class="n">population</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">rand</span><span class="p">()</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">population</span><span class="p">))]</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">rand</span><span class="p">()</span>
<span class="k">if</span> <span class="mi">0</span> <span class="o"><</span> <span class="n">t</span> <span class="o"><=</span> <span class="mf">0.33</span><span class="p">:</span>
<span class="n">P</span> <span class="o">=</span> <span class="n">papa</span><span class="o">.</span><span class="n">Kp</span>
<span class="n">I</span> <span class="o">=</span> <span class="n">mama</span><span class="o">.</span><span class="n">Ki</span>
<span class="n">D</span> <span class="o">=</span> <span class="n">mama</span><span class="o">.</span><span class="n">Kd</span>
<span class="k">elif</span> <span class="mf">0.33</span> <span class="o"><</span> <span class="n">t</span> <span class="o"><=</span> <span class="mf">0.66</span><span class="p">:</span>
<span class="n">P</span> <span class="o">=</span> <span class="n">mama</span><span class="o">.</span><span class="n">Kp</span>
<span class="n">I</span> <span class="o">=</span> <span class="n">papa</span><span class="o">.</span><span class="n">Ki</span>
<span class="n">D</span> <span class="o">=</span> <span class="n">mama</span><span class="o">.</span><span class="n">Kd</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">P</span> <span class="o">=</span> <span class="n">mama</span><span class="o">.</span><span class="n">Kp</span>
<span class="n">I</span> <span class="o">=</span> <span class="n">mama</span><span class="o">.</span><span class="n">Ki</span>
<span class="n">D</span> <span class="o">=</span> <span class="n">papa</span><span class="o">.</span><span class="n">Kd</span>
<span class="n">population</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">pid</span><span class="o">.</span><span class="n">PID</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">I</span><span class="p">,</span> <span class="n">D</span><span class="p">))</span>
<span class="c">#all the other mate randomly and mutate a bit</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">POPULATION</span><span class="o">/</span><span class="mi">3</span> <span class="o">-</span> <span class="mi">1</span><span class="p">):</span>
<span class="n">papa</span> <span class="o">=</span> <span class="n">population</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">rand</span><span class="p">()</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">population</span><span class="p">))]</span>
<span class="n">mama</span> <span class="o">=</span> <span class="n">population</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">rand</span><span class="p">()</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">population</span><span class="p">))]</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">rand</span><span class="p">()</span>
<span class="k">if</span> <span class="mi">0</span> <span class="o"><</span> <span class="n">t</span> <span class="o"><=</span> <span class="mf">0.33</span><span class="p">:</span>
<span class="n">P</span> <span class="o">=</span> <span class="n">papa</span><span class="o">.</span><span class="n">Kp</span> <span class="o">+</span> <span class="n">mutation</span><span class="p">(</span><span class="n">MAX_P</span> <span class="o">*</span> <span class="n">MUTATION_SCALE</span><span class="p">)</span>
<span class="n">I</span> <span class="o">=</span> <span class="n">mama</span><span class="o">.</span><span class="n">Ki</span> <span class="o">+</span> <span class="n">mutation</span><span class="p">(</span><span class="n">MAX_I</span> <span class="o">*</span> <span class="n">MUTATION_SCALE</span><span class="p">)</span>
<span class="n">D</span> <span class="o">=</span> <span class="n">mama</span><span class="o">.</span><span class="n">Kd</span> <span class="o">+</span> <span class="n">mutation</span><span class="p">(</span><span class="n">MAX_D</span> <span class="o">*</span> <span class="n">MUTATION_SCALE</span><span class="p">)</span>
<span class="k">elif</span> <span class="mf">0.33</span> <span class="o"><</span> <span class="n">t</span> <span class="o"><=</span> <span class="mf">0.66</span><span class="p">:</span>
<span class="n">P</span> <span class="o">=</span> <span class="n">mama</span><span class="o">.</span><span class="n">Kp</span> <span class="o">+</span> <span class="n">mutation</span><span class="p">(</span><span class="n">MAX_P</span> <span class="o">*</span> <span class="n">MUTATION_SCALE</span><span class="p">)</span>
<span class="n">I</span> <span class="o">=</span> <span class="n">papa</span><span class="o">.</span><span class="n">Ki</span> <span class="o">+</span> <span class="n">mutation</span><span class="p">(</span><span class="n">MAX_I</span> <span class="o">*</span> <span class="n">MUTATION_SCALE</span><span class="p">)</span>
<span class="n">D</span> <span class="o">=</span> <span class="n">mama</span><span class="o">.</span><span class="n">Kd</span> <span class="o">+</span> <span class="n">mutation</span><span class="p">(</span><span class="n">MAX_D</span> <span class="o">*</span> <span class="n">MUTATION_SCALE</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">P</span> <span class="o">=</span> <span class="n">mama</span><span class="o">.</span><span class="n">Kp</span> <span class="o">+</span> <span class="n">mutation</span><span class="p">(</span><span class="n">MAX_P</span> <span class="o">*</span> <span class="n">MUTATION_SCALE</span><span class="p">)</span>
<span class="n">I</span> <span class="o">=</span> <span class="n">mama</span><span class="o">.</span><span class="n">Ki</span> <span class="o">+</span> <span class="n">mutation</span><span class="p">(</span><span class="n">MAX_I</span> <span class="o">*</span> <span class="n">MUTATION_SCALE</span><span class="p">)</span>
<span class="n">D</span> <span class="o">=</span> <span class="n">papa</span><span class="o">.</span><span class="n">Kd</span> <span class="o">+</span> <span class="n">mutation</span><span class="p">(</span><span class="n">MAX_D</span> <span class="o">*</span> <span class="n">MUTATION_SCALE</span><span class="p">)</span>
<span class="n">population</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">pid</span><span class="o">.</span><span class="n">PID</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">I</span><span class="p">,</span> <span class="n">D</span><span class="p">))</span>
<span class="c">#just for the kicks add a random one</span>
<span class="n">population</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">pid</span><span class="o">.</span><span class="n">PID</span><span class="p">(</span><span class="n">rand</span><span class="p">()</span> <span class="o">*</span> <span class="n">MAX_P</span><span class="p">,</span> <span class="n">rand</span><span class="p">()</span> <span class="o">*</span> <span class="n">MAX_I</span><span class="p">,</span> <span class="n">rand</span><span class="p">()</span> <span class="o">*</span> <span class="n">MAX_D</span><span class="p">))</span>
<span class="c">#and one mutation of alpha personally</span>
<span class="n">P</span> <span class="o">=</span> <span class="n">alpha</span><span class="o">.</span><span class="n">Kp</span> <span class="o">+</span> <span class="n">mutation</span><span class="p">(</span><span class="n">MAX_P</span> <span class="o">*</span> <span class="n">MUTATION_SCALE</span><span class="p">)</span>
<span class="n">I</span> <span class="o">=</span> <span class="n">alpha</span><span class="o">.</span><span class="n">Ki</span> <span class="o">+</span> <span class="n">mutation</span><span class="p">(</span><span class="n">MAX_I</span> <span class="o">*</span> <span class="n">MUTATION_SCALE</span><span class="p">)</span>
<span class="n">D</span> <span class="o">=</span> <span class="n">alpha</span><span class="o">.</span><span class="n">Kd</span> <span class="o">+</span> <span class="n">mutation</span><span class="p">(</span><span class="n">MAX_D</span> <span class="o">*</span> <span class="n">MUTATION_SCALE</span><span class="p">)</span>
<span class="n">population</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">pid</span><span class="o">.</span><span class="n">PID</span><span class="p">(</span><span class="n">P</span><span class="p">,</span> <span class="n">I</span><span class="p">,</span> <span class="n">D</span><span class="p">))</span>
<span class="k">return</span> <span class="n">population</span></code></pre></figure>
<p>I have to note that I’m aware there are zillions of evolutionary frameworks for Python over the net, but my point here was to try the most naive uninitiated approach just to see if it works and experience the limitations and issues firsthand.</p>
<h2 id="let-it-live">Let it live!</h2>
<p>This is how the best controller out of a random population of 9 looks like
<img src="/assets/images/2013-12-01_genetics_first.png" alt="" /></p>
<p>After something like 25 generations
<img src="/assets/images/2013-12-01_genetics_middle.png" alt="" /></p>
<p>And the final winner after 50 generations
<img src="/assets/images/2013-12-01_genetics_final.png" alt="" /></p>
<p>Making the population bigger and running simulation for more generations makes the result better - the overshoot is gone and there is almost no ringing. This one came out after running 50 generations with the population of 180.
<img src="/assets/images/2013-12-01_genetics_better.png" alt="" /></p>
<h1 id="lets-try-it-on-the-real-plant">Let’s try it on the real plant!</h1>
<p>Well, remember, we had a real plant we are modelling. The whole point of the excercise was to determine PID coefficients for a real plant.</p>
<p><img src="/assets/images/2013-12-01_pid_on_real_plant.png" alt="" /></p>
<p>The green line on a plot is the output of my toy plant and it follows the model pretty closely. Suffice it to say, I’m very statisfied with the results and can’t wait to try this on a real kiln!</p>
<h1 id="conclusions">Conclusions</h1>
<ul>
<li>Modelling of a system by using its impulse response to determine the optimal PID coefficients is a feasible approach.</li>
<li>Genetic algorithms tend to be vulnerable to the problem of getting stuck in the local minima. Using a bigger population to “cover more teritory” is one way to overcome that.</li>
<li>Evaluation fuction has to be carefully selected for a particular application - for some cases big overshoot can be an acceptable compromise when quickly reaching a setpoint is a priority and vice versa.</li>
<li>The method can benefit from more insight into population dynamics - more diverse population could lead to better results when solution over several local minima has to be chosen.</li>
</ul>
Replacing Webasto HL24 clean air fan bearingsrxdtxd2013-11-20T00:00:00+02:00https://wemakethings.net/2013/11/20/webasto_hl24_replacing_bearings<h1 id="introduction">Introduction</h1>
<p>Here we have a fine specimen of the Webasto diesel heater family, a unit of some age, no longer in production, grandfather of AirTop 2000 and a respectable chap all the way. Needs its clean air fans’ bearings replaced.</p>
<p><img src="/assets/images/2013.11.20-01-webasto_hl24_side.jpg" alt="" /></p>
<p>This here will be a guide on performing service on a seemingly unserviceable part.</p>
<h1 id="getting-to-the-first-bearing">Getting to the first bearing</h1>
<p>Remove the top.</p>
<p><img src="/assets/images/2013.11.20-02-top_off.jpg" alt="" /></p>
<p>Take a look at the bottom.</p>
<p><img src="/assets/images/2013.11.20-03-bottom.jpg" alt="" /></p>
<p>It is held by two long screws on the top, they need an allen key.</p>
<p><img src="/assets/images/2013.11.20-04-inner_screws.jpg" alt="" /></p>
<p>Cold air intake cover has a protruding that keeps it attached to the metal case.</p>
<p><img src="/assets/images/2013.11.20-05_cold_air_intake.jpg" alt="" /></p>
<p>Intake fan is secured with a clip. Gently pull to remove.</p>
<p><img src="/assets/images/2013.11.20-06-fan.jpg" alt="" /></p>
<p>Unscrew 4 screws to remove the motor’s outer plastic cover. Don’t tear the o-ring inside. Don’t lose it either.</p>
<p><img src="/assets/images/2013.11.20-07-fan_off.jpg" alt="" /></p>
<p>The cover has a switch to prevent operation without the cover. It is connected with two blue wires.</p>
<p><img src="/assets/images/2013.11.20-08-motor_cover_off.jpg" alt="" /></p>
<p>The motor has another o-ring.</p>
<p><img src="/assets/images/2013.11.20-09-motor_oring.jpg" alt="" /></p>
<p>Take the motor and inner fan assembly out. Inspect the o-ring.</p>
<p><img src="/assets/images/2013.11.20-10-motor_removed.jpg" alt="" /></p>
<p><img src="/assets/images/2013.11.20-11-motor_with_inner_fan.jpg" alt="" /></p>
<p>Unscrew the motor’s cover.</p>
<p><img src="/assets/images/2013.11.20-12-motor_cap_removed.jpg" alt="" /></p>
<p>Remove the first bearing.</p>
<p>I didn’t have a bearing puller this small, so I went and bought the smallest they had. Then, I cut out a C-shaped piece of sheet metal (1 mm) to be inserted under the bearing and pulled against. Don’t try to <a href="/2013/10/12/miner_in_a_fridge_and_radeon_5850_disassembly/">triforce</a>, you’ll break the stator mount (brown).</p>
<h1 id="getting-to-the-second-bearing">Getting to the second bearing</h1>
<p>Pull out the aforementioned.</p>
<p><img src="/assets/images/2013.11.20-13-first_bearing_and_stator_removed.jpg" alt="" /></p>
<p>Pull off the motor shell.</p>
<p><img src="/assets/images/2013.11.20-14-motor_shell_removed.jpg" alt="" /></p>
<p>Now, put the remaining assembly in a vice. Start slowly heating the inner fan (around the rotor shaft) with a hand-held burner (or anything similarly low-powered). Pry the fan off bit by bit – it is best to have a few spare hands.</p>
<p>When the spacing becomes wide enough, carefully remove it with a bearing puller. The aluminum alloy is brittle, so if any force is involved, stop pulling and apply more heat around the shaft.</p>
<p>Given time and patience, the fan will come off.</p>
<p><img src="/assets/images/2013.11.20-15-rotor_and_inner_fan_in_vice.jpg" alt="" /></p>
<p>The bearing will become visible.</p>
<p><img src="/assets/images/2013.11.20-16-bottom_closeup.jpg" alt="" /></p>
<p>Using same bearing puller and discretion, it is possible to push out the rotor shaft.</p>
<p><img src="/assets/images/2013.11.20-17-rotor_removed.jpg" alt="" /></p>
<p>To remove the bearing, the four “lips” have to be broken off. The alloy is too brittle.</p>
<p><img src="/assets/images/2013.11.20-18-second_bearing_closeup.jpg" alt="" /></p>
<h1 id="remainder">Remainder</h1>
<p>Replace second bearing. Gently push in the metal at the broken-off corners to form new “lips”.</p>
<p>As to everything else, follow the above backwards. Replace seals and o-rings (yeah, right).</p>
DIY soap moldskipras2013-11-07T00:00:00+02:00https://wemakethings.net/2013/11/07/diy-soap-mold<p>Last spring I remembered my old idea – to make some soap. For a few more months I had been just pondering this, but finally I did it!</p>
<p><img src="/assets/images/2013-11-07-plywood-parts.jpg" alt="Parts cut from plywood" /></p>
<p>The experiment was successful. Since that day I have felt an incomprehensible need to make more and more of it. However, now I want to tell you not about the soap crafting process itself, but about the molds which I’ve made. Mold is a very important tool, because some manufacture processes, convenience and aesthetics of the resulting soap depend on it.</p>
<p><img src="/assets/images/2013-11-07-soap-mold-starting.jpg" alt="Assembling the mold" /></p>
<p>Since the first attempt I had decided not to pour the soap into all kinds of rubbish like yoghurt packages or empty cans, despite the fact that some people do so.</p>
<p><img src="/assets/images/2013-11-07-soap-mold-sliding-scales.jpg" alt="Assembling the mold 2" /></p>
<p>I say: one batch – one mold. Cutting soap into pieces is pure fun and the best part of the process.</p>
<p><img src="/assets/images/2013-11-07-finished-molds.jpg" alt="Finished molds" /></p>
<p>So… That time I have made my approximately one-liter mold out of 6 or 8 mm plywood, which was laying under my table. Actually, I’ve been using tools and materials which I had at home.</p>
<p><img src="/assets/images/2013-11-07-soap-poured.jpg" alt="Pouring soup" /></p>
<p>It was so poorly-made that one edge of it came unglued while making my second batch and the soap started to leak. Luckily I saw it at the beginning, otherwise it would have leaked all over my shelf. It was a great lesson: if you wanna do something seriously you need serious tools.</p>
<p><img src="/assets/images/2013-11-07-soap-poured.jpg" alt="Pouring soup" /></p>
<p>I hadn’t even thought about buying them before coming to our workshop and finding everything what I had needed for this small project. However, I (as probably more people too) have a trauma since high school technologies lessons, where we used to make netting boxes out of the thinnest plywood using a hand saw and PVA glue. In the end I made 5 molds.</p>
<p><img src="/assets/images/2013-11-07-soap_in_mold.jpg" alt="Starting to cut" /></p>
<p>Making things with proper tools is so fun! These molds are probably the most precise things that I have ever made. Working with that weird sliding angle one can mark things really accurately, than cut them easily with disc saw. All in all, now I become interested not only in soap-making but in woodworking too.</p>
<p><img src="/assets/images/2013-11-07-soap-cut.jpg" alt="Cutting the soap" /></p>
Guitar wall hangershrqkipras2013-11-06T00:00:00+02:00https://wemakethings.net/2013/11/06/guitar-wall-hanger<p>Not long ago we (<em>shrq</em> and <em>Kipras</em>) began to be annoyed by the mess in our rehearsal studio that hosts a lot of people. So the two of us decided to clean up the 13-guitar-mess in the corner and make a proper place to hang them. With a bit of thinking and some sketching we decided to make a one long wall hanger that would hold several guitars.</p>
<p>When we had a simple blueprint we started preparing the materials and the parts.</p>
<p><img src="/assets/images/2013-11-06-parts1.jpg" alt="The parts, 1" /></p>
<p><img src="/assets/images/2013-11-06-parts2.jpg" alt="The parts, 2" /></p>
<p>When the parts were finished we welded them with a MIG welder. The distance between the pipes is 6 cm so as to hold the guitar head. Afterwards we found out that this distance is slightly too large, though.</p>
<p><img src="/assets/images/2013-11-06-welding1.jpg" alt="Welding" /></p>
<p>Later on we started preparing the part of the construction that would be holding the whole weight of the guitars. Thus we decided to make supports for every hanger. The distance between the hangers has to be wide enough to allow putting in and taking out a guitar freely.</p>
<p><img src="/assets/images/2013-11-06-welding2.jpg" alt="Welding 2" /></p>
<p>Both of us really wanted to weld, so we split the job in equal parts as it is much more fun this way.</p>
<p><img src="/assets/images/2013-11-06-welding3.jpg" alt="Welding 3" /></p>
<p><img src="/assets/images/2013-11-06-welding4.jpg" alt="Welding 4" /></p>
<p>All we had left to do was isolate the metal parts from touching the guitars. So we used some styrofoam we had found in a garbage container, and a bicycle tire tube.</p>
<p><img src="/assets/images/2013-11-06-padding.jpg" alt="Soft padding" /></p>
<p>Not much was left to do then, except fixing the hanger on the wall. Though it’s not perfect this is much better than a pile of guitars.</p>
<p><img src="/assets/images/2013-11-06-fucking-metal.jpg" alt="Guitars" /></p>
TRIAC BLOC - a solid-state relay with I2C interfacemiceuz2013-10-27T00:00:00+03:00https://wemakethings.net/2013/10/27/triac-bloc<p><img src="/assets/images/2013-10-27_triac-bloc.jpg" alt="TRIAC BLOC" /></p>
<p>From time to time I get requests to make some high power switching, so I decided to design a solid-state relay that could handle a lot of different situations. The most common use for it I have is refurbishing old ceramic kilns. Since our technical life is close to the stage (both theatre and music), I also wanted it to be usable as a dimmer module. And, just for kicks, as a single phase AC motor speed controller, in case we would want that.</p>
<p>So here it goes. The design and code are on github: <a href="https://github.com/Miceuz/triac-bloc">https://github.com/Miceuz/triac-bloc</a>. I still have some spare boards and parts if anyone is interested - drop me a note (mic at wemakethings.net). Update 2014-06-05 since people are still interested in this, I’ve decided to make triac bloc available on Tindie: <a href="https://www.tindie.com/products/miceuz/triac-bloc-i2c-controllable-ssrdimmer-module?ref=offsite_badges&utm_source=sellers_miceuz&utm_medium=badges&utm_campaign=badge_small"><img src="https://d2ss6ovg47m0r5.cloudfront.net/badges/tindie-smalls.png" alt="I sell on Tindie" width="200" height="55" /></a></p>
<p>Features:</p>
<ul>
<li>maximum power - 6kW</li>
<li>zero crossing detection</li>
<li>controllable via I2C protocol</li>
<li>linear output power control</li>
<li>phase shift dimmer mode</li>
<li>switch at zero-crossing mode</li>
<li>output filtering for dimmer mode</li>
<li>snubber network</li>
<li>“low level” zero-crossing signal output</li>
<li>triac trigger signal input</li>
<li>4 spare MCU pins available for additional features</li>
<li>open source hardware and firmware</li>
</ul>
<p>Since deep in my heart I’m still a programmer, I wanted digital control that would solve some issues, like being able to set the output power in a linear manner. But nevertheless, the module is still usable without a microcontroller - zero-crossing and turn on signals are available on a separate header on the board. You can add or remove components based on particular needs. No need for dimming or motor control? Skip the filter choke and snubber. Want to integrate it into existing digital solution? Skip the micro and use zc and trigger signals directly.</p>
<h1 id="syncing-mcu-to-the-mains-frequency">Syncing MCU to the mains frequency</h1>
<p>When designing a board I went cheap and didn’t add a crystal for oscillator - “it will run just fine on the internal one” was my thinking. While assembling the board it hit me - how the hell I’m going to keep the precise timing if my oscillator is off?</p>
<p>Fortunately, ATtiny supports internal oscillator frequency tuning by adjusting the OSCCAL register. What’s cool is that this allows me to tune perfectly into the mains frequency! And it can retune itself to account for temperature drift! Everything went better than expected. This is how I’m doing it:</p>
<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="kr">inline</span> <span class="kt">void</span> <span class="nf">adjustOscillatorSpeed</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">oscAjdustDelayCounter</span><span class="o">++</span> <span class="o">></span> <span class="mi">128</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="n">periodLength</span> <span class="o">></span> <span class="mi">10060</span><span class="p">)</span> <span class="p">{</span>
<span class="n">OSCCAL</span><span class="o">--</span><span class="p">;</span>
<span class="n">calibrationGood</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">periodLength</span> <span class="o"><</span> <span class="mi">9940</span><span class="p">){</span>
<span class="n">OSCCAL</span><span class="o">++</span><span class="p">;</span>
<span class="n">calibrationGood</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">calibrationGood</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">oscAjdustDelayCounter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kr">inline</span> <span class="kt">void</span> <span class="nf">calibrate</span><span class="p">()</span> <span class="p">{</span>
<span class="kt">uint8_t</span> <span class="n">calibration</span> <span class="o">=</span> <span class="n">eeprom_read_byte</span><span class="p">(</span><span class="mh">0x00</span><span class="p">);</span>
<span class="k">if</span><span class="p">(</span><span class="n">calibration</span> <span class="o">!=</span> <span class="mi">255</span><span class="p">)</span> <span class="p">{</span>
<span class="n">OSCCAL</span> <span class="o">=</span> <span class="n">calibration</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">while</span><span class="p">(</span><span class="o">!</span><span class="n">calibrationGood</span><span class="p">)</span> <span class="p">{</span>
<span class="n">ledOn</span><span class="p">(</span><span class="n">RED</span><span class="p">);</span>
<span class="n">_delay_ms</span><span class="p">(</span><span class="mi">300</span><span class="p">);</span>
<span class="n">ledOff</span><span class="p">(</span><span class="n">RED</span><span class="p">);</span>
<span class="n">ledOn</span><span class="p">(</span><span class="n">GREEN</span><span class="p">);</span>
<span class="n">_delay_ms</span><span class="p">(</span><span class="mi">300</span><span class="p">);</span>
<span class="n">ledOff</span><span class="p">(</span><span class="n">GREEN</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">eeprom_write_byte</span><span class="p">(</span><span class="mh">0x00</span><span class="p">,</span> <span class="n">OSCCAL</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<h1 id="zero-crossing-detection">Zero crossing detection</h1>
<p>I chose the cheap way of doing that - just a pair of resistors and an AC optocoupler.</p>
<p><img src="/assets/images/2013-10-27_zc-schematics.jpg" alt="zc schematic" /></p>
<p>This works pretty well, but introduces some weird behaviour. In reality I can not accuratelly detect the zero-crossing event, as any of the LEDs in the optocoupler will go out before the real zero crossing will happen, so what I am getting is a wide pulse around zero crossing and the true zero crossing should happen in the very middle of that pulse. To get around this I’ve started plotting graphs of pulse widths I get.</p>
<p><img src="/assets/images/2013-10-27_zc-pulse-length.jpg" alt="zc pulse length" /></p>
<p>The most of the noise probably could be accounted to the noise present on the AC line - some peaks of the AC sine are higher, then I get narrower pulses, some are lower for wider zc pulses I detect. But hold on. I played a bit with resistor values and plotted this graph, showing distribution of widths of two adjacent pulses.</p>
<p><img src="/assets/images/2013-10-27_zc-pulse-histogram1.jpg" alt="zc pulse length" /></p>
<p>What. A. hell? How come two adjacent pulse lengths are bound to happen in such a uniform manner? While I was posting to the eevblog forum for help, I took a photo of the scope and everything instantly became clear - the two LEDs in the optocoupler ARE NOT IDENTICAL. As you would expect. So I’m really seeing difference in the forward voltage drop of the LEDs. The scope picture shows two superimposed pulses, one for positive half cycle of AC sine, another for - negative.</p>
<p><img src="/assets/images/2013-10-27_zc-scope.jpg" alt="ZC on scope" /></p>
<p>Well, in general, this was just a scientific detour as errors I get because of this are totally insignificant. I used this knowledge while writing the firmware - I always expect the next ZC pulse to be the same length as the previous one. This way I get 100uS error max, that makes max 1% of total half-period length and cancels the temperature drift of resistors and LEDs.</p>
<p><img src="/assets/images/2013-10-27_zc-pulse-histogram2.jpg" alt="zc pulse length" /></p>
<h1 id="power-output-linearization">Power output linearization</h1>
<p>As AC voltage is sinusoidal and the power in our Universe is proportional to the voltage squared, we are getting the power output to be the integral of the sine squared. Something like this:</p>
<p><img src="/assets/images/2013-10-27_power-integral.jpg" alt="zc pulse length" /></p>
<p>This equation is not easy to solve when you want to get the conduction angle <em>t</em> for desired power <em>P</em>. <em>opit</em> presented great help on this, I’ve used the Newton - Raphson method to solve the equation and to build a table which I’ve used in the firmware:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c">#solving x - sin(x) = C, f(x) = C - 2x + sin(2x) </span>
<span class="c">#derivative f'(x) = -4sin^2(x)</span>
<span class="c">#x[n+1] = x[n] - f(x[n])/f'(x[n])</span>
<span class="kn">import</span> <span class="nn">math</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="kn">as</span> <span class="nn">plt</span>
<span class="kn">from</span> <span class="nn">matplotlib.ticker</span> <span class="kn">import</span> <span class="n">MultipleLocator</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="kn">as</span> <span class="nn">np</span>
<span class="k">def</span> <span class="nf">guess</span><span class="p">(</span><span class="n">y</span><span class="p">):</span>
<span class="k">return</span> <span class="n">y</span><span class="o">/</span><span class="mi">2</span><span class="p">;</span>
<span class="k">def</span> <span class="nf">fderivative</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
<span class="k">return</span> <span class="o">-</span><span class="mi">4</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
<span class="k">return</span> <span class="mi">4</span> <span class="o">*</span> <span class="n">y</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">x</span> <span class="o">+</span> <span class="n">math</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">x</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">solveIteration</span><span class="p">(</span><span class="n">xPrevious</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
<span class="k">if</span> <span class="mi">0</span> <span class="o">==</span> <span class="n">fderivative</span><span class="p">(</span><span class="n">xPrevious</span><span class="p">):</span>
<span class="k">return</span> <span class="n">xPrevious</span>
<span class="k">return</span> <span class="n">xPrevious</span> <span class="o">-</span> <span class="n">f</span><span class="p">(</span><span class="n">xPrevious</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span><span class="o">/</span><span class="n">fderivative</span><span class="p">(</span><span class="n">xPrevious</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">solve</span><span class="p">(</span><span class="n">y</span><span class="p">):</span>
<span class="n">x</span><span class="o">=</span><span class="n">math</span><span class="o">.</span><span class="n">pi</span><span class="o">/</span><span class="mi">2</span><span class="p">;</span><span class="c">#guess(y)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">100</span><span class="p">):</span> <span class="c"># 100 iterations proves to be enough</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">solveIteration</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
<span class="k">return</span> <span class="n">x</span>
<span class="n">maxConductionAngle</span> <span class="o">=</span> <span class="mi">10000</span>
<span class="n">conductionAngles</span><span class="o">=</span><span class="nb">range</span><span class="p">(</span><span class="n">maxConductionAngle</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">maxConductionAngle</span><span class="p">):</span>
<span class="n">conductionAngles</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">solve</span><span class="p">(</span><span class="n">math</span><span class="o">.</span><span class="n">pi</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">/</span> <span class="p">(</span><span class="n">maxConductionAngle</span><span class="p">)</span> <span class="o">*</span> <span class="n">i</span><span class="p">);</span>
<span class="n">xvalues</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">maxConductionAngle</span> <span class="o">*</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">xvalues</span> <span class="o">=</span> <span class="p">(</span><span class="n">xvalues</span><span class="o">/</span><span class="n">np</span><span class="o">.</span><span class="nb">max</span><span class="p">(</span><span class="n">xvalues</span><span class="p">))</span><span class="o">*</span><span class="mi">100</span>
<span class="n">table</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">256</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">256</span><span class="p">):</span>
<span class="n">j</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">i</span> <span class="o">*</span> <span class="n">maxConductionAngle</span> <span class="o">/</span> <span class="mf">255.0</span><span class="p">)</span>
<span class="k">print</span> <span class="n">i</span><span class="p">,</span> <span class="n">j</span>
<span class="k">if</span> <span class="n">j</span> <span class="o"><</span> <span class="mi">10000</span><span class="p">:</span>
<span class="n">table</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">conductionAngles</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">/</span> <span class="n">math</span><span class="o">.</span><span class="n">pi</span> <span class="o">*</span> <span class="mi">10000</span><span class="p">;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">table</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">10000</span><span class="p">;</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">256</span><span class="p">):</span>
<span class="k">print</span> <span class="n">table</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="s">","</span>
<span class="n">conductionAngles</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">conductionAngles</span><span class="p">)</span>
<span class="n">fig</span><span class="o">=</span><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">111</span><span class="p">)</span>
<span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">set_minor_locator</span><span class="p">(</span><span class="n">MultipleLocator</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
<span class="n">ax</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="bp">True</span><span class="p">,</span> <span class="n">which</span><span class="o">=</span><span class="s">'both'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">xvalues</span><span class="p">,</span> <span class="n">conductionAngles</span><span class="o">/</span><span class="n">math</span><span class="o">.</span><span class="n">pi</span><span class="o">*</span><span class="mi">10000</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s">"conduction angle, degrees"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s">"power, </span><span class="si">%</span><span class="s">"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span>
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">table</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]),</span> <span class="n">table</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></code></pre></figure>
<p>We get essentially this graph:</p>
<p><img src="/assets/images/2013-10-27_power-linearization.jpg" alt="zc pulse length" /></p>
<h1 id="load-testing">Load testing</h1>
<p>I’ve done numerous light dimming tests and one high power test. I’ve hooked up TRIAC BLOC to one heater element of a kiln we will be using for our upcomming pyrolysis project (more on this later some time). The resistance of the cold heating element is 9 Ohms, this in theory should give me 26A of current, in practice I’ve measured 23.8A, that’s 5.7kW. Below you can see my test prototype employing a tiny heatsink for this amount of power. The triac was at 77 degrees Celsius which is probably too high, but I was not able to destroy it. The filter choke was warm to touch, high power tracs too - the fan blowing onto this probably would be totally appropriate. As you can see, I’ve taken advantage of spare MCU pins and hooked up a pot for manual control.</p>
<p><img src="/assets/images/2013-10-27_prototype.jpg" alt="zc pulse length" /></p>
Miner-in-a-fridge and Radeon 5850 disassemblyrxdtxdveox2013-10-12T00:00:00+03:00https://wemakethings.net/2013/10/12/miner_in_a_fridge_and_radeon_5850_disassembly<h1 id="intro-and-history">Intro and history</h1>
<p>I’ll take this opportunity to write about a rather old project that I did with <em>veox</em>.</p>
<p>One day, he comes up with a brilliant idea of building a so-called Bitcoin <a href="https://en.bitcoin.it/wiki/Mining">miner</a> using old video cards from eBay. The way I see it, <a href="http://bitcoin.org/en/faq">Bitcoin</a> is a technical hack to route around the global banking <a href="https://en.wikipedia.org/wiki/Ponzi_scheme">ponzi scheme</a>. “<a href="https://en.bitcoin.it/wiki/Mining">Mining</a>” is (essentially) lame slang for transaction verification and providing a deterministic money supply. These functions are performed by networked machines. Anyway, <em>veox</em> did the computer hardware part, and asked me to make a case. I also helped him with the power distribution, using these <a href="http://blog.zorinaq.com/?e=42">original</a> <a href="http://blog.zorinaq.com/?e=44">instructions</a>.</p>
<p>There was a discarded fridge taking up space in our workshop, and <em>pwf</em> suggested we get rid of it, preferably by applying creativity. Thus Frankenstein’s monster came to be. I think I made it in a day or so. There’s no build log.</p>
<h1 id="neutralise-the-offender">Neutralise the offender</h1>
<p>A few days ago, one of the GPUs started making screechy noises. Sounded like a worn-out bearing. The machine had never gotten a dust cleaning since its inception (<a href="/2012/02/14/repairing-a-martin-atomic-3000-dmx-strobe/">and I warned you!..</a>). First step – identify the malfuctioning component.</p>
<p>Finding the noisy card is easy: push down on the fan for a second, it will stop spinning. If the noise is gone, there’s your “broken” part right there. In our case, it was the second from the left.</p>
<p>At this point, I turned the machine off and took it out.</p>
<p><img src="/assets/images/2013-10-12-1-miner_and_toolcase.jpg" alt="Re-purposed fridge in what looks like a basement, computer mounted in a weded metal strip frame" /></p>
<p>There were originally two shelves and a freezer in the fridge. I took out the freezer and constrained the design so two units could fit in, potentially. One such unit could also fit in a 4U rack mount case, if such a need had ever arisen. It hasn’t, yet.</p>
<p>The briefcase on the left is my take-out electronics service kit. Some vacuum cleaner and compressor hoses are also visible.</p>
<p>Here’s a zoom-in on the unit:</p>
<p><img src="/assets/images/2013-10-12-2-miner.jpg" alt="Close-up of the computer frame" /></p>
<p>Four ATI Radeon GPUs and a 6-core AMD processor. <em>veox</em> here says that, contrary to popular sentiment, he went for above-minimum CPU power so he could do other things, too, like compile software. He adds it’s been very nice to have one when <a href="https://en.wikipedia.org/wiki/Primecoin">Primecoin</a> was released. Whatever.</p>
<p>Fridge from the inside, those fans in the back are for additional air flow, scavenged from dead UPSes, and they have to be replaced by now, too:</p>
<p><img src="/assets/images/2013-10-12-3-fridge_internals.jpg" alt="Computer on a shelf in the fridge, three fans cut into the fridge back wall above it, two power supply units in the compartment below" /></p>
<p>Cyrillic letters say “hasher”. Must be an inside joke.</p>
<h1 id="radeon-5850-disassembly">Radeon 5850 disassembly</h1>
<p>To the point – here’s the GPU:</p>
<p><img src="/assets/images/2013-10-12-4-gpu_backside.jpg" alt="ATI Radeon 5850 circuit board back side" /></p>
<p>Unscrew 10 largish screws, 4 smaller spring-loaded ones pulling down the heatsink onto the GPU chip, and also 3 small ones on the right side (not visible in the image) that hold together the metal rail and the plastic case, crack it open, and voila!</p>
<p><img src="/assets/images/2013-10-12-5-case_unscrewed.jpg" alt="ATI Radeon 5850 circuit board front side and case inside " /></p>
<p>Detach the fan power connector, unscrew 5 long screws that hold the external plastic and the internal aluminum parts of the case together, unscrew 3 short screws that hold the fan…</p>
<p>Oops, shredded one of them. No biggie, go to the workshop, weld a piece of rod to it with a TIG (15 Amps, DC):</p>
<p><img src="/assets/images/2013-10-12-6-screw_weld.jpg" alt="TIG rod welded to a screw still in the GPU case" /></p>
<p>Use that as leverage to unscrew, done!</p>
<p>The heatsink is now accessible, a good time to give it (and everything else) 8 bars of nice clean rushing air:</p>
<p><img src="/assets/images/2013-10-12-7-case_disassembled.jpg" alt="ATI Radeon 5850 OEM heatsink" /></p>
<p>To inspect the fan, one has to know <a href="https://www.youtube.com/watch?v=kH8spGRL3Yk">how to triforce</a>:</p>
<p><img src="/assets/images/2013-10-12-8-fan_triforce.jpg" alt="Fan rotor pryied up at three corners" /></p>
<p>Doesn’t look too bad. Lube it up, push it in, see if you like it.</p>
<p><img src="/assets/images/2013-10-12-9-fan_open.jpg" alt="ATI Radeon 5850 OEM fan, disassembled" /></p>
<p>To put it back together, follow the same steps in reverse. Don’t forget to change the thermal paste where appropriate. (Just in case, it’s appropriate on all chips that have a reflective surface, and those that have paste residue.)</p>
<p>To replace the one screw that got screwed, I salvaged another one from an old hard drive. Actually, I replaced all three, because what the heck.</p>
<p>After powering up, this GPU is still considerably noisier than the other three, but at least the dying sound is gone. Time enough for a replacement to get shipped.</p>
<h1 id="addendum-by-veox">Addendum by veox</h1>
<ul>
<li>This machine has been mining Bitcoin for a few weeks at most. After that, I switched it to Litecoin, and eventually Primecoin, too.</li>
<li>We had a bet with <em>rxdtxd</em>, I said he couldn’t write a post on this by the end of the week. Since I lost (obviously), I’ll have to run some <a href="https://boinc.berkeley.edu/">BOINC</a> projects on the machine for 24 hours. I bet a week of processing time your ASIC can’t do that. ;)</li>
</ul>
Summer projects, part 1. Rebuilding a smoke saunaopitpwfiochmiceuzdinamarxdtxdhroblestephshrqvarious artists2013-10-03T00:00:00+03:00https://wemakethings.net/2013/10/03/summer-sauna<p>This summer we’ve been posting quite sporadically because we were very busy with some big <em>afk</em> projects.</p>
<p><img src="/assets/images/2013-10-02-mill.jpg" alt="The mill" /></p>
<p>One of us lives in an old, solitary idle water mill in the countryside. There had been an old smoke sauna, converted from a forge. Last autumn a large ash tree fell over it, ruining the roof and the construction completely. We had decided to tear it down and build a new one, preferably as similar as possible to the original. First <em>pwf</em> made a blueprint for the wooden construction, using Google Sketchup. If you’re interested, drop us a note and we will upload it somewhere.</p>
<p><img src="/assets/images/2013-10-02-sauna-blueprint.png" alt="The blueprint" /></p>
<p>We got together at the end of June, then we were frantically packing, buying materials and tools, welding a table, a grill and a shelf, loading and unloading stuff for a week. When we landed in the countryside, we promptly tore down the old sauna. This was the easy part.</p>
<p>The ugliest job, I think, was laying the concrete foundation for the building. It was raining intermittently, we had to dig a lot of ditches, the job was dirty, rather dull, and very important.</p>
<p><img src="/assets/images/2013-10-02-mixer.jpg" alt="Rašalas" /></p>
<p><img src="/assets/images/2013-10-02-old-bricks.jpg" alt="Bricks" /></p>
<p>The old bricks. We had to reuse them, and it was a major pain in the ass: the bricks’ age spanned some 100 years, and their height ranged between 5 and 9.5 cm.</p>
<p><img src="/assets/images/2013-10-02-tree1.jpg" alt="Tree1" /></p>
<p><img src="/assets/images/2013-10-02-tree2.jpg" alt="Tree2" /></p>
<p>Sadly, we had to cut a huge ash tree that was growing next to the site. It was old and its roots were already rotten. <em>ioch</em> climbed up and chopped down the branches, then <em>pwf</em> finished it with a chainsaw.</p>
<p><img src="/assets/images/2013-10-02-construction-site.jpg" alt="Clean field" /></p>
<p>When the foundations were ready, <em>dinama</em> and <em>miceuz</em> set to work on the construction, whereas me, <em>ioch</em>, <em>Steph</em> and <em>shrq</em> tasked ourselves with the brick walls of the warm chamber of the sauna. I’ve been whining a lot and <em>ioch</em> sprained his back, but at least I’ve got some decent biceps now.</p>
<p><img src="/assets/images/2013-10-02-construction-progress.jpg" alt="Construction" /></p>
<p><img src="/assets/images/2013-10-02-bricks.jpg" alt="Bricks" /></p>
<p><img src="/assets/images/2013-10-02-nature-morte.jpg" alt="A Nature Morte" /></p>
<p><img src="/assets/images/2013-10-02-sauna-splash.jpg" alt="River" /></p>
<p>All this consumed a better part of the month, together with some other projects that had sprung up in a fractal manner. At least the river was close.</p>
<p><img src="/assets/images/2013-10-02-wreath.jpg" alt="The crown" /></p>
<p>The construction is finished. Note the spectator’s armchair.</p>
<p><img src="/assets/images/2013-10-02-sauna-stove.jpg" alt="The sauna stove" /></p>
<p>The sauna stove, designed/built/welded by <em>ioch</em>.</p>
<p><img src="/assets/images/2013-10-02-sauna-exterior.jpg" alt="Exterior" /></p>
<p>Finished exterior walls, by <em>rxdtxd</em> and <em>hroble</em>. The doors are authentic.</p>
<p>The sauna was tested upon completion, and, barring some minor mishaps (like me and <em>pwf</em> making really uncomfortable benches during the last night, or the stove cracking and a window falling out), it turned out to be quite awesome. Now it even has a chandelier.</p>
<p><img src="/assets/images/2013-10-02-sauna-interior.jpg" alt="Inside" /></p>
<p>Interior – the outer room. The chandelier pulley is visible above the sofa.</p>
<p><img src="/assets/images/2013-10-02-sauna-hot.jpg" alt="Inside -- sauna room" /></p>
<p>Inside the sauna chamber, darkened after a few uses. The scribble on the tin ceiling says ‘CLOSE THE DOOR’.</p>
<p><img src="/assets/images/2013-10-02-chandelier-side.jpg" alt="Chandelier" /></p>
<p><em>pwf</em> and <em>dinama</em> made a 10 cd chandelier out of an old carriage wheel. Raised and lowered with a pulley.</p>
<p><img src="/assets/images/2013-10-02-chandelier-bottom.jpg" alt="Chandelier" /></p>
Fixing a HAMEG HM 605miceuz2013-09-29T00:00:00+03:00https://wemakethings.net/2013/09/29/hameg-fix<p><img src="/assets/images/2013-09-29_hameg-HM605.jpg" alt="HAMEG HM 605" /></p>
<p>I had two choices while considering my ‘scope upgrade: to either shell out for a Rigol entry-level scope or buy a used analogue one. Since the prices for the secondhand scopes of respectable brands on ebay are not that far away from those of a brand new Rigol, I decided I want a journey and bought myself a defective Hameg HM 605. It’s a basic dual-input 60MHz oscilloscope with some nice trigger delay/hold off features - just a little bit more powerful than I currently need, but hey, it’s a journey after all!</p>
<p>The scope came defective as advertised - it was displaying a single dot. The triggering was working, I could adjust the y position of the dot but it wouldn’t move on x axis. I was hoping that this was just a power supply problem and surely enough, I instantly noticed a suspiciously warm transformer. Upon opening a case, I found one of diode brigde rectifiers was toast too and after some poking with multimeter in continuity mode I’ve found a shorted electrolytic cap on 140V rail. This rail goes to X amplifier circuit - no wonder why the trace does not move horizontally.</p>
<p>The only 100V capable cap I could find around was salvaged from some abandoned TV set. Too big to fit into the case, so I bodged it.</p>
<p><img src="/assets/images/2013-09-29_bodge.jpg" alt="Bodged cap" /></p>
<p>I didn’t bother to do a proper job here, since I just wanted to test the fix and order some proper caps later.</p>
<p><img src="/assets/images/2013-09-29_bodge-closeup.jpg" alt="Bodged cap closeup" /></p>
<p>Well, the scope worked perfectly ok. For a week. Now the trace was shorter than the width of the screen. Aha, problems on another rail! When another of the old caps finally went bananas, the screen began to show this:</p>
<p><img src="/assets/images/2013-09-29_bliau2.jpg" alt="bliau" /></p>
<p>It was triggerring ok-ish in “line” trigger mode, so apparently I was seeing power coming straight from the power supply. To be more precise, sometimes NOT coming.</p>
<p><img src="/assets/images/2013-09-29_bliau3.2.jpg" alt="bliau2" /></p>
<p>So I finally got the caps and replaced them all.
<img src="/assets/images/2013-09-29_bad-caps.jpg" alt="bad caps" /></p>
<p>There was some hassle to get to the board containing filter electrolytics. I had to disassemble a bunch of button and potentiometer shafts and unsolder wires coming from a transformer.</p>
<p><img src="/assets/images/2013-09-29_trafo-conn.jpg" alt="Transformer taps" /></p>
<p>Some of the heatsinked devices were isolated from a heatsink, so I took a photo before unscrewing them.</p>
<p><img src="/assets/images/2013-09-29_heatsinked.jpg" alt="Heatsinked devices" /></p>
<p>Well, that was a smooth journey - I got lucky the defect to be that trivial. The scope is working fine, and I’m a happy panda. Probably I will sell it sometime and finally get a midrange digital one for a shitload of money, but hey, where’s the fun part of that?</p>
<p><img src="/assets/images/2013-09-29_fixed.jpg" alt="Fixed" /></p>
Experimenting with cat purropitmiceuz2013-08-31T00:00:00+03:00https://wemakethings.net/2013/08/31/experimenting-with-cat-purr<p>A few years ago I had seen a <a href="http://theoatmeal.com/comics/cat_know">comic by Oatmeal</a> claiming that cats purr at the same frequency as idling diesel engines. Thinking that it was a highly amusing fact I went on to record <a href="/assets/sounds/2013-08-31-diesel.wav">the sound</a> of my friend’s <a href="/assets/images/2013-08-31-ufoliner.jpg">bus</a> (a MB 100), <a href="/assets/sounds/2013-08-31-alfa.wav">the purr</a> of <a href="/assets/images/2013-08-31-alfa.jpg">my feline overlord</a> and <a href="/assets/sounds/2013-08-31-katyte.wav">that</a> of another young kitten.</p>
<p>At the time we’ve been organising local geek nights in our city. I ran all the recordings through some graphical Fourier-analysis software I no longer use, included a few more cat purr recordings from the Internet for the sake of consistency and gave a short talk one night.</p>
<p><img src="/assets/images/2013-08-31-alfa-fft.png" alt="Alpha FFT" /></p>
<p>The frequency of Alpha’s purr, it appeared, was 28 Hz.</p>
<p><img src="/assets/images/2013-08-31-kitten-fft.png" alt="Cat FFT" /></p>
<p>The other cat, which had a really loud and distinctive purr, had a frequency of 27 Hz.</p>
<p><img src="/assets/images/2013-08-31-ufoliner-fft.png" alt="Ufoliner FFT" /></p>
<p>The diesel engine was idling at 22 Hz.</p>
<p>Since both cats were female and I was not happy with the recording of the engine, I downloaded and recordings of 7 more cats purring, as well as the sound <a href="/assets/images/2013-08-31-truck.jpg">of a big diesel truck</a>. This engine had a dominant frequency at 24 Hz, whereas the mean of all cat frequency peaks was at 26.1 Hz. Having decided that these sounds are reasonably similar I happily forgot about it all, until a few hours ago when I thought that cat purr would be a great sound for our upcoming anti-alarm clock that <em>miceuz</em> and <em>ioch</em> were building.</p>
<p><em>miceuz</em> used a random motor from a scanner to emit the artificial purr. He attached a displaced weight to the motor’s shaft. An ATMega 328P microcontroller drives the motor through a MOSFET transistor by feeding a 24 Hz square wave while varying pulse width for “inhalations” and “exhalations”. Added a pinch of random to inhalation and exhalation duration.</p>
<iframe width="480" height="360" src="//www.youtube.com/embed/M0un74hBnng" frameborder="0" allowfullscreen="1">e</iframe>
<p>All the parts seen on the video except the motor have nothing to do with the circuit.</p>
<p>The code that is presented below is just an AVR code that can be run on arduino:</p>
<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="n">byte</span> <span class="n">purrCounter</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="n">byte</span> <span class="n">threshold</span> <span class="o">=</span> <span class="mi">15</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="n">TCCR1A</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">TCCR1B</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">TCCR1B</span> <span class="o">|=</span> <span class="n">_BV</span><span class="p">(</span><span class="n">CS12</span><span class="p">)</span> <span class="o">|</span> <span class="n">_BV</span><span class="p">(</span><span class="n">CS10</span><span class="p">)</span> <span class="o">|</span> <span class="n">_BV</span><span class="p">(</span><span class="n">WGM12</span><span class="p">);</span>
<span class="n">OCR1A</span> <span class="o">=</span> <span class="mi">651</span><span class="p">;</span>
<span class="n">OCR1B</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
<span class="n">TIMSK1</span> <span class="o">|=</span> <span class="n">_BV</span><span class="p">(</span><span class="n">OCIE1A</span><span class="p">);</span>
<span class="n">TIMSK1</span> <span class="o">|=</span> <span class="n">_BV</span><span class="p">(</span><span class="n">OCIE1B</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">SIGNAL</span><span class="p">(</span><span class="n">TIMER1_COMPA_vect</span><span class="p">)</span> <span class="p">{</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">SIGNAL</span><span class="p">(</span><span class="n">TIMER1_COMPB_vect</span><span class="p">)</span> <span class="p">{</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="n">LOW</span><span class="p">);</span>
<span class="n">purrCounter</span><span class="o">++</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="n">purrCounter</span> <span class="o">></span> <span class="n">threshold</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="n">OCR1B</span> <span class="o">==</span> <span class="mi">10</span><span class="p">)</span> <span class="p">{</span>
<span class="n">OCR1B</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="n">threshold</span> <span class="o">=</span> <span class="mi">13</span> <span class="o">+</span> <span class="n">random</span><span class="p">(</span><span class="mi">6</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">OCR1B</span><span class="o">=</span><span class="mi">10</span><span class="p">;</span>
<span class="n">threshold</span> <span class="o">=</span> <span class="mi">26</span> <span class="o">+</span> <span class="n">random</span><span class="p">(</span><span class="mi">18</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">purrCounter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
Chirp! - the plant watering alarmmiceuz2013-06-07T00:00:00+03:00https://wemakethings.net/2013/06/07/chirp-plant-watering-alarm<p>I’m a programmer/systems architect by education and by the way of winning bread, but somehow I got infected with the electronics bug 3 years ago - had a sidejob to upgrade the firmware of a LED display, got into microcontrollers, then made myself comfortable in analog.</p>
<p><a href="http://eevblog.com">Dave Jones</a> has been saying in his videos - go on, make a product. So <a href="http://wemakethings.net/chirp">I’ve made one</a> - even probably built “down to a price” at some extent. It is <a href="https://www.tindie.com/products/miceuz/chirp-plant-watering-alarm/">available for sale on Tindie</a>, but read on…</p>
<p><img src="/assets/images/2012.11.27-plant_watering_alarm-avers.jpg" alt="plant watering alarm - averse" /></p>
<p>It’s a “plant watering alarm” - you set the dry point, then water the plant and then it starts to chirp when the plant dries out. Chirps are rare at the beginning and more frequent when the water level gets really low. It has a LED hooked up as a light sensor, so it does not make noise at night.</p>
<p><img src="/assets/images/2012.11.27-plant_watering_alarm-revers.jpg" alt="plant watering alarm - reverse" /></p>
<p>I decided on a capacitive moisure sensing technique as it is superior to the resistive one - the circuit is totally isolated from the soil, thus it avoids problems with corrosion, battery life, electro-chemical effects and is more reliable and repeatable in general.</p>
<p>The first approach I’ve tried was straightforward - charge an unknown capacitance and measure the time it takes to discharge through known resistance. This works really well when building a makeshift capacitance meter for a lab, but wasn’t really suitable for my purposes. The noise was a problem - when capacitance is so low, you have to increase MCU speed and add a rather big resistance to get some decent dynamic range. This high impedance point picks up all kinds of noise that might be impossible to filter out because of aliasing. Another drawback - high speed and filtering in software implies external oscillator - this affects the battery life and BOM cost.</p>
<p>So I went with another capacitive sensing approach where a square wave is fed into a RC filter formed by known resistance and unknown capacitance as a wide track on the board. The filtered waveform is triangle-like. It is a half-wave rectified by a diode and stored into a capacitor that has a bleeder resistor. When the capacitance changes, the peaks of the waveform become lower or higher resulting in changing voltage in the storage capacitor. Go to <a href="http://wemakethings.net/2012/09/26/capacitance_measurement/">http://wemakethings.net/2012/09/26/capacitance_measurement/</a> for a more detailed explanation. The concept can be illustrated by this picture:</p>
<p><img src="/assets/images/2012.09.26-capacitance_measurement_idea.png" alt="Capacitance measurement idea" /></p>
<p>I’m feeding 1MHz from an internal RC oscillator of attiny44 micro. I measured the capacitance of my sensor to be around 4.3pf - 75pf, used the same board to measure this, so the measurements might be a bit off. I had put some effort to calculate and measure the most optimal filter resistor value, so I would get the widest range and then I looked for the shape of the sensor track so it would give me more range. I decided against using an opamp as I was building this down to a price - as much as possible had to be done in micro and in discrete analog. The range I got is 508 - 833 LSB which is pretty enough for the application.</p>
<p>Isolating the circuit from soil moisture was a bitch - water seeps through almost any stuff eventually. The combination I found to be pretty OK was a piece of scotch tape and some varnish spray designed for electronics. Epoxy works too, but it lowers the range and the thing is not really designed to be covered in it.</p>
<p>The great and interesting challenge was to extend the battery life. I set myself a goal of 1 year on a cr2032 battery and learned many tricks how to get the current consumption down, this was real fun:
* slow down CPU speed when doing the slow stuff
* sleep all the time with only a watchdog running; I used watchdog interrupt to wake up every 8 seconds and do the measurements every 255 wakeups
* turn off every peripheral that is not used at the moment
* have a switch to turn stuff external to the microcontroller off</p>
<p>The Chirp can operate in two modes - alarm mode and sensor mode. In sensor mode it does not conserve battery at all and is providing capacitance measurements by I2C. I used a reset trick to switch the modes - the button on the board is tied to reset line, the micro saves a flag in eeprom on boot and clears it after a second. If the flag is not present - the Chirp goes into the sensor mode, so double-clicking the button makes the Chirp a dumb sensor.</p>
<p>Regarding the PCB manufacturing - waiting for orders from China, screwing up with gerber files and playing mail ping-pong between the Western New Year and the Chinese New Year - man, what can I say - this stuff is depressing.</p>
<p>All said, I’m not certain what path should I take with it - the most win for the project would be if it would get cloned by the Chinese, otherwise it’s a somewhat pricy and somehow silly widget. I’m selling it prebuilt on <a href="https://www.tindie.com/products/miceuz/chirp-plant-watering-alarm/">Tindie</a>, but it might be more fun for people to build one, so I’m considering to sell it as a kit, but SMD kits is another silly idea - <a href="mailto:mic$wemakethings.net">let me know</a> what you think.</p>
<p>I’m using it myself for a half a year and surprisingly - it still works on the same battery. The flowers have died though, but for other reasons.</p>
<p><img src="/assets/images/2012.11.27-plant-watering-alarm.jpg" alt="plant watering alarm" /></p>
dmx-dimmer 19-inch rack mount caserxdtxd2013-05-18T00:00:00+03:00https://wemakethings.net/2013/05/18/dmx-dimmer-case<p>I first thought of buying a pre-made 19-inch rack mount case, 3U high, 19 inches deep, but those were unavailable locally, and shipping such a large item would cost a fortune. Even if one was available, I’d still have to cut out holes for screws and air vents, which would take too much time.</p>
<p>Instead, <em>pwf</em> suggested I order a custom-made one, cut out with a water jet and folded at a shop that specialises in doing just that.</p>
<p>The shop needed an AutoCAD .dawg file for their machines. I don’t have AutoCAD, so used <a href="http://free-cad.sourceforge.net/">FreeCAD</a> instead. It went better than <a href="/2012/12/06/merry-go-round/">last time</a>, especially since this time I used its sketch feature and constraints a-la SolidWorks.</p>
<p>But it doesn’t export directly to .dwg, only .dxf. <a href="http://www.draftsight.com/">Draftsight</a> can handle both, though, so I exported to .dxf in FreeCAD, imported that in Draftsight, moved things around to coloured layers, exported to .dwg and sent the file to the shop. A little convoluted, sure. The files are available <a href="https://github.com/rxdtxd/rack3u/">here</a>.</p>
<p>The shop didn’t quite do it by-the drawing, since I didn’t include a 3D view of what I was expecting. (DraftSight is essentially AutoCAD for 2D, at least the free version.) Also, I made some poor design choices in my drawing, so there was more work to do on the case than initially anticipated.</p>
<p>First, I didn’t specify the bending radii, and didn’t account for the thickness (1 mm) of the sheet metal in the cutout. Then, I went for the bottom-and-four-sides being one piece, instead of bottom-and-two-sides, so the shop couldn’t fold the box perfectly. I had to align it up before welding two adjacent sides.</p>
<p>Also note that had I gone the bottom-and-two-sides + top-and-two-sides route, no welding would have been necessary. Maybe I’ll fix that in some future revision of the drawing, if I ever need a 19” rack again.</p>
<p><img src="/assets/images/2013.05.18-1-clamp.jpg" alt="A large clamp for initial alignment" /></p>
<p>Sheet metal doesn’t dissipate heat so well. To prevent warpage, I clamped in a brass “heatsink” on the backside:</p>
<p><img src="/assets/images/2013.05.18-2-clamp.jpg" alt="Two clamps holding a brass piece at a corner" /></p>
<p>Clamps are good arm rests, too:</p>
<p><img src="/assets/images/2013.05.18-3-clamp-hand-rest.jpg" alt="Using a clamp for very comfortable" /></p>
<p>I also didn’t include two mounting brackets for the DIN rail holding the circuit breakers, so had to hammer those out and plug-weld them from the front side of the case:</p>
<p><img src="/assets/images/2013.05.18-4-din-rail-brackets.jpg" alt="Brackets inside the case to attach a din rail with circuit breakers" /></p>
<p>Then, I forgot to include screw holes for the top, so had to drill and tap those. Here’s how it looks:</p>
<p><img src="/assets/images/2013.05.18-5-case.jpg" alt="Case with top lid" /></p>
<p>Bent a few pieces of 6 mm rod, tapped their ends, cut out a front plate from 2 mm sheet metal, drilled two pairs of holes on either side and welded the rods in as handles. Also drilled two pairs of holes for the rack mounting screws, and cut out rectangular pieces for the front panel stuff:</p>
<p><img src="/assets/images/2013.05.18-6-panel-with-handles.jpg" alt="Front plate, showing how the handles attach it to the case" /></p>
<p>Cleaned the case, covered in primer, painted black. Got no photos of that.</p>
<p>Mounted the electonics inside. The bottom looks screwed:</p>
<p><img src="/assets/images/2013.05.18-7-bottom.jpg" alt="Bottom of the case" /></p>
<p>Those rectangular holes are for air flow, they’re right beneath the triacs’ heatsinks.</p>
<p><img src="/assets/images/2013.05.18-8-wires-mess.jpg" alt="All modules mounted in case, the wires still a mess" /></p>
<p>The wires were a mess, tidied them up with zip-ties, attached to these neat little adhesive zip-tie holders:</p>
<p><img src="/assets/images/2013.05.18-9-wires-tidy.jpg" alt="Wires tidied up with zip ties" /></p>
<p>The original Sherlock Holmes Pipe is included for size comparison.</p>
<p>That’s almost it! Once I get to run a final power test, with the top lid screwed in place, I’ll do a final rant, promise to update the schematics, PCB layout and case drawing, conveniently forget all of that, and move on to other extremely time-consuming stuff.</p>
dmx-dimmer power testsrxdtxd2013-04-13T00:00:00+03:00https://wemakethings.net/2013/04/13/dmx-dimmer-power-tests<p><a href="/2013/03/03/winding-chokes-for-the-dmx-dimmer/">Last time</a> I mentioned the chokes were buzzing too much, so I’d have to dip them in epoxy. Doing that helped somewhat with the noise, and I expect it to be a non-issue once they’re in a closed case.</p>
<p><img src="/assets/images/2013.04.13-chokes_in_epoxy.jpg" alt="Three slaves without heatsinks, with chokes covered in epoxy" /></p>
<p>It took me a few days or so to wire it all up – stripping wires, checking the power cable, yada-yada.</p>
<p>I couldn’t run it at full-power just yet. Software was being non-cooperative. Previously, I’ve tested the system with the master and just one slave. Now, with three slaves connected, there were conflicts. One of them was all the slaves using the same physical OK line. (After the master sends an interrupt, the slave uses that to signal it’s ready to receive data.) How silly of me. Luckily, there were still some unused pins on the master board, so I didn’t have to invent a yet another multiplexer, and just use separate OK lines. It’s all in the <a href="https://github.com/rxdtxd/dmx-dimmer">code</a> now, and the schematic, too, but I haven’t propagated it to the PCB (as of this writing).</p>
<p>That didn’t fix another problem: the master locking up, as if all slaves were receiving an interrupt, even though separate lines have always been used for that. After a few days of bewilderment, I decided to do the one thing which is known to solve issues almost universally. Namely, get drunk.</p>
<p>The hangover helped me in looking over the design calmly and realising that, although the interrupt lines are separate, the Master-In-Slave-Out is connected to all three slaves, and they are not in Hi-Z state by default. There is no reason for the master to receive data from slaves, really, other than verifying the slave is functional. But rather than disconnecting the MISO line, I fixed it in software.</p>
<p>After that, I was finally able to run the full-power tests. The heatsink goes to 50 °C in half an hour, and stays that way, with 8 kW (4 channels set at 100%). Triacs’ package was 5-10 °C above that. So with heatsinks as big as these, I might not even need a fan in the case, alhough that is yet to be proven.</p>
<p><img src="/assets/images/2013.04.13-45_deg.jpg" alt="45 degrees celsius on the heatsink" /></p>
<p>Still there were 3 more things to do with software:</p>
<ul>
<li>DMX address selection – turned out two address lines got accidentally swapped; fixed in software, not fixed in hardware;</li>
<li>setting preheat an maximum value – involved mucking with ADC multiplexing, and I eventually convinced myself this is <em>not</em> needed at all, and should be handled by the lighting console anyway; the UNIX philosophy works in hardware, too: do one thing and do it well (well, try at least);</li>
<li>setting a light curve – chopping a sinusoid’s half-period in 256 equal parts means the lower and upper percentage changes give a small delta in output power, whereas the middle is rather sensitive.</li>
</ul>
<p>The last one is rather important, and I thought it could be solved by chopping the half-period in non-equal parts. That didn’t work: either the timer interrupt routine wasn’t fast enough, or you can’t really change a timer’s TOP value while the timer is running in CTC mode. Turning the timer off, changing the TOP and then turning it back on helped, but it introduced an unacceptable lag. Modifying the timer value to accomodate the lag sounds like too much guesswork. Bored with the project by now, I decided not to implement this feature.</p>
<p>Here’s a dirty Python script I used to generate the timer’s values. Note that a 16 bit timer is required with these if no prescaling is used.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c">#!/usr/bin/env python</span>
<span class="kn">import</span> <span class="nn">math</span>
<span class="n">a</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">b</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c"># tmp = 0</span>
<span class="n">step</span> <span class="o">=</span> <span class="mf">2.0</span><span class="o">/</span><span class="mi">256</span>
<span class="n">durzc</span> <span class="o">=</span> <span class="p">[]</span> <span class="c"># duration (total time) passed from zero crossing</span>
<span class="n">delays</span> <span class="o">=</span> <span class="p">[]</span> <span class="c"># duration between two durzc values</span>
<span class="n">cycles</span> <span class="o">=</span> <span class="mf">6000000.0</span><span class="o">/</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="mi">50</span><span class="p">)</span> <span class="c"># cycles between two zero crossings</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">255</span><span class="p">):</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">acos</span><span class="p">(</span><span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">-</span> <span class="n">step</span><span class="p">)</span>
<span class="c"># print(n, a, b) # debug</span>
<span class="n">durzc</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">b</span><span class="o">/</span><span class="n">math</span><span class="o">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">*</span> <span class="n">cycles</span><span class="p">)</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">b</span>
<span class="n">durzc</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="mf">1.0</span> <span class="o">*</span> <span class="n">cycles</span><span class="p">)</span>
<span class="c"># print(durzc) # debug</span>
<span class="n">delays</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">durzc</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">256</span><span class="p">):</span>
<span class="n">delays</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">durzc</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">-</span> <span class="n">durzc</span><span class="p">[</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
<span class="n">delays</span> <span class="o">=</span> <span class="p">[</span><span class="nb">round</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">delays</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="n">delays</span><span class="p">)</span>
<span class="c"># for n in range(0,256):</span>
<span class="c"># tmp += delays[n]</span>
<span class="c"># print(tmp) # debug</span></code></pre></figure>
<p>Its output, slightly formatted:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>[2389, 992, 762, 644, 569, 515, 475, 443,
417, 395, 376, 360, 346, 334, 323, 313,
304, 296, 288, 281, 275, 269, 264, 258,
254, 249, 245, 241, 237, 234, 230, 227,
224, 221, 218, 216, 213, 211, 209, 207,
204, 202, 201, 199, 197, 195, 194, 192,
190, 189, 187, 186, 185, 183, 182, 181,
180, 179, 178, 177, 176, 175, 174, 173,
172, 171, 170, 169, 169, 168, 167, 166,
166, 165, 164, 164, 163, 162, 162, 161,
161, 160, 160, 159, 159, 158, 158, 157,
157, 156, 156, 156, 155, 155, 155, 154,
154, 154, 153, 153, 153, 153, 152, 152,
152, 152, 151, 151, 151, 151, 151, 150,
150, 150, 150, 150, 150, 150, 150, 150,
149, 149, 149, 149, 149, 149, 149, 149,
149, 149, 149, 149, 149, 149, 149, 149,
150, 150, 150, 150, 150, 150, 150, 150,
150, 151, 151, 151, 151, 151, 152, 152,
152, 152, 153, 153, 153, 153, 154, 154,
154, 155, 155, 155, 156, 156, 156, 157,
157, 158, 158, 159, 159, 160, 160, 161,
161, 162, 162, 163, 164, 164, 165, 166,
166, 167, 168, 169, 169, 170, 171, 172,
173, 174, 175, 176, 177, 178, 179, 180,
181, 182, 183, 185, 186, 187, 189, 190,
192, 194, 195, 197, 199, 201, 202, 204,
207, 209, 211, 213, 216, 218, 221, 224,
227, 230, 234, 237, 241, 245, 249, 254,
258, 264, 269, 275, 281, 288, 296, 304,
313, 323, 334, 346, 360, 376, 395, 417,
443, 475, 515, 569, 644, 762, 992, 2389]
</code></pre>
</div>
<p>And, finally, the whole thing, all wired and waiting for a case:</p>
<p><img src="/assets/images/2013.04.13-wired.jpg" alt="Dimmer completely wired, still on the cardboard" /></p>
Welding a Palm Sunday bouquetopitpwf2013-03-09T00:00:00+02:00https://wemakethings.net/2013/03/09/welding-a-palm-sunday-bouquet<p>A <a href="https://en.wikipedia.org/wiki/Easter_palm">‘Palm Sunday bouquet’</a>, an ‘Easter palm’, <em>‘verba’</em> or <em>‘Palma wielkanocna’</em> is a Lithuanian/Polish contraption used by local Catholics for Easter rituals. Since no palm trees grow here, people started making their own out of willow and juniper branches, dried herbs and flowers and other stuff. They are, as a rule, ugly dust collectors (the bouquets).</p>
<p>Several years ago I thought about welding them from junk and putting them up for sale during a spring fair, simply for fun. Now, I couldn’t weld two things together without melting half of the planet, but <em>pwf</em> can and so he made an Easter palm out of old cutlery we had around. Just for the sake of implementing the idea.</p>
<p><img src="/assets/images/2013-03-09-palm1.jpg" alt="Easter palm1" /></p>
<p>He washed away the old fat and dust, then cut off the plastic handles and welded spoons/knifes/forks together with a TIG welder. There was also a selling story about Lithuanian bridal customs and killing wild elks with a <em>verba</em>, but it was lost during a period of inebriation that followed.</p>
Winding chokes for the dmx-dimmerrxdtxd2013-03-03T00:00:00+02:00https://wemakethings.net/2013/03/03/winding-chokes-for-the-dmx-dimmer<p>It’s that time of the year again, and I’ve been working these past few weeks on the dmx-dimmer project: putting it together on a piece of cardboard a-la science fair, re-designing the power dimmer module, and running power tests.</p>
<p><a href="/2012/04/09/dmx-dimmer-ready-for-testing/">Last visit</a> I mentioned winding my own chokes (inductors). These will be used for rush current suppression in the power line, so they need not be precise and uniform.</p>
<p>We salvage ferrites among other things, and there was enough wire laying around. If I had to buy either of these, doin’ it myself would’ve been more expensive that buying pre-made ones – provided, of course, the local shop carries them at all.</p>
<p>Anyway, I started out by smoothing the straight edges on my ferrites, otherwise laquer on the wires would’ve gotten damaged during bending, which means spark gaps. Used a small round file for the first one, but it took too long, so switched to a hand-held rotary tool with a sanding stone drillbit. On the image below, the smoothed toroid is on the right.</p>
<p><img src="/assets/images/2013.03.03-1-ferrite_cores.jpg" alt="Toroidal ferrite cores" /></p>
<p>Then I cut two pieces of 1 mm copper wire, both 90 cm long (determined by trial). I removed laquer on their ends using sand paper, since none of the solvents we had on hand worked. <em>ioch</em> speculated it could be done in boiling base, but we haven’t tried that.</p>
<p><img src="/assets/images/2013.03.03-2-core_and_clean_wires.jpg" alt="Core in a vise, two copper wires with laquer stripped at the ends" /></p>
<p>I clamp the ferrite in a vise with some padding, put a pair of straigtened wires through the hole and, well, start winding. This requires both hands to constantly press the wire to the ferrite, keep gaps as small as possible, prevent wire arcing and bending, get equal spacing and many other things that take many other words to describe.</p>
<p>If you intend doing something like this, I suggest practice first. There’s nothing about chokes but getting the hang of it.</p>
<p><img src="/assets/images/2013.03.03-3-choke_half_wound.jpg" alt="A core is a vise with double wire wrapped halfway around the toroid" /></p>
<p>After one half is done, turn it around in the vise. Ideally, it should be perfectly symmetric when finished. In practice, one of my first chokes looked something like this:</p>
<p><img src="/assets/images/2013.03.03-4-choke_wound.jpg" alt="A finished choke on graph paper" /></p>
<p>Not too bad, really.</p>
<p>Before I solder them into the boards, I decided to check if any laquer got damaged after all, and see if they burn. So I cut them into the phase line of the mains, one at a time:</p>
<p><img src="/assets/images/2013.03.03-5-choke_temp_measure.jpg" alt="Choke in series with mains" /></p>
<p>On the other end sits a 2 kW load of light fixtures. The chokes heat up to 40 °C. The blown socket in the picture above is from an unrelated experiment.</p>
<p>I’ve also tested one with the new dimmer module, and it works, but noisily (as in sound). Which means I’ll be dipping them into epoxy.</p>
<p><img src="/assets/images/2013.03.03-6-results.jpg" alt="Three populated slave boards, a dozen chokes and one 4-channel dimmer board, populated except for a few headers and the chokes" /></p>
<p>In the image above, from bottom to top: three populated slave boards; a dozen chokes; and one 4-channel dimmer board, missing a few caps, a few headers, and the inductors, of course.</p>
<p>As always, all <a href="https://github.com/rxdtxd/dmx-dimmer">design files are available on GitHub</a>.</p>
How does an ADC work?miceuz2013-02-25T00:00:00+02:00https://wemakethings.net/2013/02/25/how-does-adc-work<p>This is a little experiment on how does a SAR ADC work.</p>
<center><iframe width="420" height="315" src="http://www.youtube.com/embed/VpfKXuaalJo" frameborder="0" allowfullscreen="true">e</iframe></center>
<p>A register, a DAC, a comparator and some control logic make an ADC. To perform a conversion, a binary search is performed. Bits in the register are turned on consecutevely from most significant bit to least significant one. If the voltage at the DAC output is higher than the voltage ADC is digitizing, the bit is turned off, if it’s lower, the bit is left on.</p>
<p>What I don’t mention in the video is how accuracy of resistors is important and how different kinds of errors creep in, but it’s a very broad topic on itself. Suffice to say that resistors should be as accurate as possible to get a linear response with low offset and gain errors.</p>
<p>One more thing to mention is that usually there is a so called “sample and hold” capacitor at the “unknown voltage” input of ADC where the voltage is sampled before the conversion so that rapidly changing input does not affect the reading.</p>
<p>This is schematic and Arduino code if someone wants to try it themselves.</p>
<p><img src="/assets/images/2013-02-25-adc-schematic.jpg" alt="adc schematic" /></p>
<p><img src="/assets/images/2013-02-15-adc-breadboard.jpg" alt="adc breadboard" /></p>
<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="cp">#define COMPARATOR 8
#define BUTTON 9
</span>
<span class="cm">/* button states */</span>
<span class="cp">#define PRESSED 1
#define MAYBE_PRESSED 2
#define RELEASED 3
#define MAYBE_RELEASED 4
</span><span class="n">byte</span> <span class="n">buttonState</span> <span class="o">=</span> <span class="n">RELEASED</span><span class="p">;</span>
<span class="n">byte</span> <span class="n">lastButtonState</span> <span class="o">=</span> <span class="n">RELEASED</span><span class="p">;</span>
<span class="cm">/* the mask bit we are shifting each step */</span>
<span class="n">byte</span> <span class="n">mask</span> <span class="o">=</span> <span class="mi">0</span><span class="n">b10000000</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="n">DDRD</span> <span class="o">=</span> <span class="mh">0xFF</span><span class="p">;</span> <span class="c1">//port D set to output (digital outputs 0 to 7)
</span> <span class="n">PORTD</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">//all bits off
</span> <span class="n">pinMode</span><span class="p">(</span><span class="n">COMPARATOR</span><span class="p">,</span> <span class="n">INPUT</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">BUTTON</span><span class="p">,</span> <span class="n">INPUT</span><span class="p">);</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">BUTTON</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span> <span class="c1">//turn a puu up for a button on
</span><span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="n">PORTD</span> <span class="o">|=</span> <span class="n">mask</span><span class="p">;</span> <span class="c1">//turn on one bit
</span> <span class="k">while</span><span class="p">(</span><span class="o">!</span><span class="n">buttonPress</span><span class="p">()){</span> <span class="c1">//wait for the button press for demo purposes
</span> <span class="c1">//NOTHING
</span> <span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="n">LOW</span> <span class="o">==</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">COMPARATOR</span><span class="p">))</span> <span class="p">{</span>
<span class="n">PORTD</span> <span class="o">&=</span> <span class="o">~</span><span class="n">mask</span><span class="p">;</span> <span class="c1">//if comparator turns on, turn off the bit
</span> <span class="p">}</span>
<span class="n">mask</span> <span class="o">=</span> <span class="n">mask</span> <span class="o">>></span> <span class="mi">1</span><span class="p">;</span> <span class="c1">//shift for next bit
</span>
<span class="k">if</span><span class="p">(</span><span class="mi">0</span> <span class="o">==</span> <span class="n">mask</span><span class="p">)</span> <span class="p">{</span>
<span class="k">while</span><span class="p">(</span><span class="o">!</span><span class="n">buttonPress</span><span class="p">()){</span>
<span class="c1">//NOTHING
</span> <span class="p">}</span>
<span class="n">mask</span> <span class="o">=</span> <span class="mi">0</span><span class="n">b10000000</span><span class="p">;</span>
<span class="n">PORTD</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">while</span><span class="p">(</span><span class="o">!</span><span class="n">buttonPress</span><span class="p">()){</span>
<span class="c1">//NOTHING
</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="cm">/* button debouncing routine */</span>
<span class="n">boolean</span> <span class="nf">buttonPress</span><span class="p">()</span> <span class="p">{</span>
<span class="n">byte</span> <span class="n">button</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">BUTTON</span><span class="p">);</span>
<span class="k">switch</span><span class="p">(</span><span class="n">buttonState</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">MAYBE_PRESSED</span><span class="p">:</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="k">if</span><span class="p">(</span><span class="n">LOW</span> <span class="o">==</span> <span class="n">button</span><span class="p">)</span> <span class="p">{</span>
<span class="n">buttonState</span> <span class="o">=</span> <span class="n">PRESSED</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">buttonState</span> <span class="o">=</span> <span class="n">RELEASED</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="n">PRESSED</span><span class="p">:</span>
<span class="k">if</span><span class="p">(</span><span class="n">HIGH</span> <span class="o">==</span> <span class="n">button</span><span class="p">)</span> <span class="p">{</span>
<span class="n">buttonState</span> <span class="o">=</span> <span class="n">MAYBE_RELEASED</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="n">MAYBE_RELEASED</span><span class="p">:</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="k">if</span><span class="p">(</span><span class="n">HIGH</span> <span class="o">==</span> <span class="n">button</span><span class="p">)</span> <span class="p">{</span>
<span class="n">buttonState</span> <span class="o">=</span> <span class="n">RELEASED</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">buttonState</span> <span class="o">=</span> <span class="n">PRESSED</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="n">RELEASED</span><span class="p">:</span>
<span class="k">if</span><span class="p">(</span><span class="n">LOW</span> <span class="o">==</span> <span class="n">button</span><span class="p">)</span> <span class="p">{</span>
<span class="n">buttonState</span> <span class="o">=</span> <span class="n">MAYBE_PRESSED</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">boolean</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">lastButtonState</span> <span class="o">!=</span> <span class="n">buttonState</span> <span class="o">&&</span> <span class="n">PRESSED</span> <span class="o">==</span> <span class="n">buttonState</span><span class="p">;</span>
<span class="n">lastButtonState</span> <span class="o">=</span> <span class="n">buttonState</span><span class="p">;</span>
<span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
Near Earth objects impact probabilitiesopitrxdtxd2013-02-22T00:00:00+02:00https://wemakethings.net/2013/02/22/neo-impact-probabilities<p><a href="http://www.astronomynotes.com/solfluf/s5.htm">Collisions with rocks from space</a> are hot news these days. <em>rxdtxd</em> posted the link to <a href="http://neo.ssa.esa.int/web/guest/risk-page">ESA Near Earth Objects risk table</a>, I started playing with it since it was a new shiny distraction, and because we are quite oblivious to what the raw data has to say.</p>
<p>Humans are rather incapable at internalising numbers – we did not evolve to manage risks rationally. We skim over tables with horrifying observations (say, ocean acidification) and shrug, but duck and run from a tiger-shaped bush, because it suddenly seems so urgent and personal.</p>
<p><img src="/assets/images/2013-02-22-esa_probs.png" alt="ESA log probabilities" /></p>
<p>These are logarithms of impact probabilities over the next 100 years or so, based on ESA data. Sizes of dots are proportional to volumes of meteorites (<a href="https://en.wikipedia.org/wiki/Spherical_cow">assuming they are spherical</a>): the largest one corresponds to <a href="http://neo.ssa.esa.int/web/guest/search-for-objects?sum=1&des=2010AU118">2010AU118</a>, a 1200 m diameter rock that’s supposed to fly nearby sometime in 2015. The smallest object in the sample is 2 meters across.</p>
<p>NASA also maintains <a href="http://neo.jpl.nasa.gov/risk/">its impact risk table</a>, without any machine-friendly download options, however. <em>rxdtxd</em>, being a very technical boy, used a <a href="https://github.com/rxdtxd/asterisks/blob/master/chewnasa.sh">tangle of regexps</a> to parse it (I’d have gone with <a href="http://www.crummy.com/software/BeautifulSoup/">the Beautiful Soup</a>, as I’m lazy). Some of the objects in these tables match.</p>
<p>The NASA table is curious: they do not provide possible impact dates, only intervals when an object might be of any danger. And they probably calculate impact probabilities in a different way than ESA. I used the middle year of those intervals as a possible impact date in the following plot, which throws the NASA and ESA data together.</p>
<p><img src="/assets/images/2013-02-22-probs_nasa_esa.png" alt="ESA and NASA log probabilities" /></p>
<p>A possibility of an impact tells us pretty nothing: the consequences depend on the atmospheric entry angle, composition and velocity of the object, impact location (water or rock), etc. (I didn’t know before that asteroids can <a href="http://www.phys.ncku.edu.tw/~astrolab/mirrors/apod_e/ap090302.html">graze Earth’s atmosphere and fly away</a>). I couldn’t find the exact energy yield equations during a quick browse-around, but here are a few <a href="http://impact.ese.ic.ac.uk/ImpactEffects/">more</a> or <a href="http://janus.astro.umd.edu/astro/impact/">less</a> serious calculators and <a href="http://articles.adsabs.harvard.edu//full/1958IrAJ....5...14O/0000021.000.html">an article by E. Oepik from 1958</a>. He was an Estonian astronomer way ahead of his time. We are actually quoting his letter on galaxy inclinations from <strong>1923</strong> in one of our scholarly papers!</p>
<p>Both NASA and ESA datasets offer two scales to evaluate the actual threats raised by near-Earth objects, that is, the <a href="https://en.wikipedia.org/wiki/Torino_Scale">Torino</a> and <a href="http://en.wikipedia.org/wiki/Palermo_scale">Palermo</a> scales, both combining impact probabilities and yields (kinetic energies). The former, I think, is for the mainstream media mainly – it gives a convenient, quite subjective indication of level of concern warranted. Currently there is <strong>1</strong> known object with a non-zero Torino scale rating.</p>
<p>The Palermo scale is rather complex, but more objective: it denotes relative risks with respect to background. <a href="http://neo.jpl.nasa.gov/risk/doc/palermo.html">Go read more about it here</a>.</p>
<p><img src="/assets/images/2013-02-22-nasa_esa_palermo.png" alt="ESA and NASA Palermo scale ratings" /></p>
<p>The ESA and NASA Palermo ratings do not match, though they correlate: they must be calculating the impact probabilities differently, and NASA does not provide timing for separate impact events.</p>
<p>If one sums up the impact probabilities, she gets 0.101-0.09 for ESA and NASA respectively. These are probabilities that we will be hit by an object we already know about. However, here’s the cumulative probability chart for ESA data:</p>
<p><img src="/assets/images/2013-02-22-esa_cum_prob.png" alt="ESA cumulative probabilities" /></p>
<p>The gaps denote years that have no impact probability data, nevermind them. As you can see, the majority of that 0.101 probability is due to <a href="http://neo.ssa.esa.int/web/guest/search-for-objects?sum=1&des=2010RF12">2010RF12</a>, which is a 9 m diameter rock (<a href="http://www.esa.int/Our_Activities/Operations/Russia_asteroid_impact_ESA_update_and_assessment">Chelyabinsk meteorite is assumed</a> to be twice larger, although it entered at a very low angle). Which is to say, we’ll probably will be hit by a similar-sized meteorite before RF12’s presumed impact date (well, we were hit last week without any warning!).</p>
<p>The following is rather speculative.</p>
<p>I noticed that there is an overdensity of impact probabilities around 2080. The saying goes, ‘if you don’t know what to do with your data, do a Fourier transform’. Since FT does not work well on unevenly-spaced data, I used <a href="https://en.wikipedia.org/wiki/Least-squares_spectral_analysis">Lomb-Scargle analysis</a> instead. Spectral analysis, such as L-S or Fourier analysis, is used in order to find any periodicities in time-series data, that is, finding dominant subcomponents of a signal, if there are any.</p>
<p><img src="/assets/images/2013-02-22-lomb-scargle.png" alt="LSSA periodogram" /></p>
<p>There might be a periodicity of ~37 years in the impact probabilities data, or it might be an artifact of rather short (~100 years) time interval available. It can be spurious, or maybe there is some orbital resonance with a group of NEOs.</p>
<p>One reason for the higher number of probable impact events at the end of this century might be the fact that impact probabilities are initially given larger values, and then revised downwards. As we learn of a flyby of a space rock, we know about its orbit with some certainty, and some close encounters alter the orbit of the asteroid enough to warrant attention later. (If you’re interested in what <a href="http://spaceguard.rm.iasf.cnr.it/tumblingstone/issues/num20/eng/keyhole.htm">‘a keyhole’ is, start here</a>.) So far, chances that a known small asteroid will come back are smaller than chances of being hit by an unknown rock.</p>
<p>All code we used <a href="https://github.com/astrolitterbox/Asteroids/">is here</a>. I probably won’t be bothered to make it tidy.</p>
<p>Now the disclaimer: my research area is the galaxies and quasars. I know squat about the Solar System, except that Pluto is not a planet anymore. Don’t panic, but don’t throw away your Kalashnikov and the cans of condensed milk yet.</p>
Stepper motors as rotary encodersmiceuz2013-02-18T00:00:00+02:00https://wemakethings.net/2013/02/18/steppers-as-rotary-encoders<p>I’ve spent some time playing around the idea of using stepper or brushless motors as rotary encoders.</p>
<center><iframe width="420" height="315" src="http://www.youtube.com/embed/K_WDn_PbUO0" frameborder="0" allowfullscreen="true">e</iframe></center>
<p>Stepper acts as a high impedance AC voltage source outputing sinusoidal waveform, it’s just a matter of apmlifying and converting this signal to a square wave:</p>
<p><img src="/assets/images/2013-02-18-stepper-encoder-schematics.jpg" alt="schematics" /></p>
<p>R1 and R2 set up a reference voltage, R3 and C2 low-pass filter the signal from a motor - when this signal goes above the reference voltage, comparator changes it’s output producing a nice square wave.</p>
<p>The same effect can be obtained using a high gain noninverting op amp circuit, but as opamps are not really ment to be operated in saturation regions, I’ve decided to go with a comparator.</p>
<p>You have to do this to two phases of a stepper motor - one phase will lag the other - this way you can determine a direction of rotation.</p>
<p>Here is a piece of arduinized avr code that reads the encoder and drives a single digit 7 segment display:</p>
<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="n">DDRD</span> <span class="o">=</span> <span class="mh">0xFF</span><span class="p">;</span><span class="c1">//setup port D as ouput for 7-seg display
</span> <span class="n">pinMode</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="n">INPUT</span><span class="p">);</span><span class="c1">//motor phase 1 on PORTC 0
</span> <span class="n">pinMode</span><span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="n">INPUT</span><span class="p">);</span><span class="c1">//motor phase 2 on PORTC 1
</span><span class="p">}</span>
<span class="n">byte</span> <span class="n">digits</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span>
<span class="mi">0</span><span class="n">b00000011</span><span class="p">,</span><span class="c1">//0
</span> <span class="mi">0</span><span class="n">b11110011</span><span class="p">,</span><span class="c1">//1
</span> <span class="mi">0</span><span class="n">b10000101</span><span class="p">,</span><span class="c1">//2
</span> <span class="mi">0</span><span class="n">b00001101</span><span class="p">,</span><span class="c1">//3
</span> <span class="mi">0</span><span class="n">b00111001</span><span class="p">,</span><span class="c1">//4
</span> <span class="mi">0</span><span class="n">b01001001</span><span class="p">,</span><span class="c1">//5
</span> <span class="mi">0</span><span class="n">b01000001</span><span class="p">,</span><span class="c1">//6
</span> <span class="mi">0</span><span class="n">b00011111</span><span class="p">,</span><span class="c1">//7
</span> <span class="mi">0</span><span class="n">b00000001</span><span class="p">,</span><span class="c1">//8
</span> <span class="mi">0</span><span class="n">b00001001</span><span class="p">,</span><span class="c1">//9
</span><span class="p">};</span>
<span class="n">byte</span> <span class="n">t</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">//step counter
</span><span class="n">byte</span> <span class="n">lastVal</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">//last value of motor phase inputs
</span><span class="n">byte</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">//segment which is displayed
</span><span class="n">byte</span> <span class="n">digit</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">//digit that is displayed
</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">//flash one segment every loop
</span> <span class="n">PORTD</span> <span class="o">=</span> <span class="n">digits</span><span class="p">[</span><span class="n">digit</span><span class="p">]</span> <span class="o">|</span> <span class="o">~</span><span class="p">(</span><span class="mh">0x01</span> <span class="o"><<</span> <span class="n">b</span><span class="p">);</span>
<span class="n">b</span><span class="o">++</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="n">b</span> <span class="o">></span> <span class="mi">7</span><span class="p">)</span> <span class="p">{</span>
<span class="n">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">//read status of motor pins
</span> <span class="n">byte</span> <span class="n">val</span> <span class="o">=</span> <span class="n">PINB</span> <span class="o">&</span> <span class="mh">0x03</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="n">val</span> <span class="o">!=</span> <span class="n">lastVal</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">((</span><span class="n">val</span> <span class="o">==</span> <span class="mi">3</span> <span class="o">&&</span> <span class="n">lastVal</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span>
<span class="c1">//t is just a step counter, we change the digit every 3 steps
</span> <span class="n">t</span><span class="o">++</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="mi">4</span> <span class="o">==</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span>
<span class="n">t</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">digit</span><span class="o">++</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="mi">10</span> <span class="o">==</span> <span class="n">digit</span><span class="p">)</span> <span class="p">{</span>
<span class="n">digit</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">((</span><span class="n">val</span> <span class="o">==</span> <span class="mi">2</span> <span class="o">&&</span> <span class="n">lastVal</span> <span class="o">==</span> <span class="mi">3</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="mi">0</span> <span class="o">==</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span>
<span class="n">t</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="mi">0</span> <span class="o">==</span> <span class="n">digit</span><span class="p">)</span> <span class="p">{</span>
<span class="n">digit</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">digit</span> <span class="o">--</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">t</span><span class="o">--</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">lastVal</span> <span class="o">=</span> <span class="n">val</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
Auto-off bike lightmiceuz2013-02-03T00:00:00+02:00https://wemakethings.net/2013/02/03/auto-off-bike-light<p><img src="/assets/images/2013-02-03-device.jpg" alt="device" /></p>
<p>I wanted to make an auto-off bike light because I just keep forgetting to switch it off and the batteries are constantly flat. And I hate dynamos.</p>
<p>I was looking into accelerometers, but couldn’t find one that would enter sleep mode and give me interrupts with zero configuration. This implies using microcontroller and it gets boring pretty fast. So I decided to choose the low-tech way. All I needed was a switch that would close when disturbed mechanically. After digging in various junk bins I found a spring and came up with this solution:</p>
<p><img src="/assets/images/2013-02-03-switch.jpg" alt="switch circuit" />
The schematics are simple:</p>
<p><img src="/assets/images/2013-02-03-schematics.jpg" alt="schematics" /></p>
<p>The resistor keeps the mosfet off. When the switch is closed briefly, capacitor instantly charges up above the mosfet’s gate threshold voltage, the mosfet turns on the LED. Then the capacitor discharges slowly through the resistor until its voltage drops below the gate threshold voltage, causing the mosfet to turn off. So if my spring switch closes rapidly while I ride (say, at least once in a minute), the light stays on. If I stop for more than a minute, the light goes off. I chose a 10 megaohm resistor and a 22uF capacitor, in theory this should give about 30 seconds until the threshold voltage is reached.</p>
<p>This is the switch with the circuit soldered:</p>
<p><img src="/assets/images/2013-02-03-switch_circuit.jpg" alt="circuit" /></p>
<p>A copper clad board, a knife and smd components…</p>
Open source Lithium battery charger modulesmiceuz2013-02-02T00:00:00+02:00https://wemakethings.net/2013/02/02/lithium-battery-chargers<p><img src="/assets/images/2013.02.02-li-ion-charger.jpg" alt="retarded charger" /></p>
<p>For a long time I wanted to enter the 21st century by stopping using NiCad or NiMH batteries and upgrading to Lithium accumulators as they provide more power per volume and are cool in general. Constant flow of obsolete cell phones provides a nice source of reasonably high-performance batteries for free - I felt compelled to tap into this resource for my battery operated projects.</p>
<p>Well, there are a couple of issues you have to take care of when moving to Li-ion or LiPoly:</p>
<ul>
<li>you have to charge them in a particular specific way they like</li>
<li>you can’t discharge them below a certain threshold</li>
<li>oh, yeah, did I mention they blow up violently if you screw up?</li>
</ul>
<p>What’s nice about cell phone batteries is that they usually come with a protection circuitry that protects them when they are overdischarged and short-circuited. Once we tried to blow up a cell phone battery by shorting it, connecting to external power supply in proper polarity, then in reverse polarity, then directly to 240V - the sucker just didn’t blow up! This is just how good protection circuit on cell phone batteries is.</p>
<p>Ok, enough of this retarded shit. I needed a proper way to charge batteries, and I’ve chosen USB from a computer as the primary power source since those are ubiquitous. So, to get the job done I chose to test three (essentially two) popular Li-ion charging ICs: <a href="http://www.maximintegrated.com/datasheet/index.mvp/id/4002">MAX1551</a>, <a href="http://www.maximintegrated.com/datasheet/index.mvp/id/4002">MAX1555</a> and <a href="http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en024903">MCP73831</a>.</p>
<p>There are loads of the charger designs based on these ICs on the net, but I couldn’t find one that would meet my requirements:</p>
<ul>
<li>made in Eagle</li>
<li>DIY toner transfer friendly</li>
<li>charging/finished indication</li>
<li>jumper/resistor selectable charging current</li>
<li>optional USB connector</li>
</ul>
<p>So I made my own and am posting them online for people to use: <a href="https://github.com/Miceuz/USBLiPoCharger">https://github.com/Miceuz/USBLiPoCharger</a></p>
<p><img src="/assets/images/2013.02.02-boards.jpg" alt="all the boards" /></p>
<p>MAX1551 does not provide feedback about charging status, so there’s no point talking about it. MAX1555 does provide charging status though, so I took some effort to make use of it:</p>
<p><img src="/assets/images/2013.02.02-MAX1555-schematics.png" alt="max1555 schematics" /></p>
<p>MAX1555 CHG pin is an open drain output that goes low while the battery is charging, stays high impedance otherwise. While the battery is charging, Q1 is off as its gate is pulled low, lucky combination of LEDs and MOSFETs salvaged from some motherboards allows for Q2 to turn on and light up the LED_CHARGING. When the CHG pin goes high impedance, gate of Q1 is pulled up by R2, Q1 turns on while turning on LED_CHARGED and pulling down the gate of Q2.</p>
<p>The MOSFETs I used are of jelly-bean kind with “702” marking on them, the LED_CHARGED has a voltage drop of about 1.6V, this makes a gate voltage of 5V - 1.6V = 3.4V apparently this is enough for 702 to turn on.</p>
<p>I’ve added a solder jumper that can be used to change charging current mode.</p>
<p>MCP73831 has a tri-state STAT output, this makes indication trivial:</p>
<p><img src="/assets/images/2013.02.02-MCP73831-schematics.png" alt="mcp73831 schematics" /></p>
<p>Another nice thing about MCP73831 is that it provides a possibility to tune the charging current for the size of your battery - if the battery is small, you don’t want to charge it at very high currents, probably you’d aim for 0.8 x battery capacity to be on the safe side. This can be done by selecting a suitable resistor on PROG pin - consult the datasheet. Note that you can easily violate the USB specification which does not allow for devices to draw currents higher that 100mA without negotiation. But all the USB hosts in computers I’ve met usually don’t care.</p>
<p>I’m not sure about MAX155X, but I can tell from personal experience that MCP73831 does not have any internal protection form reversed battery. It goes poof! with a tiny trace of smoke.</p>
<p>This is a photo of one of my projects - TV-B-Gone packed into a Nokia phone case utilising the original battery:</p>
<p><img src="/assets/images/2013.02.02-tvbgone.jpg" alt="tvbgone" /></p>
<p>This is a photo of a raw phone battery cell charging. The battery was old and was outputing no voltage, but after I ripped out the protection circuitry, the cell showed some 2.5V - just on the edge of becoming useless. I was able to charge it without any problems - no heating, etc. I don’t recommend this way of using old batteries, it’s here just to show how retarded I am.</p>
<p><img src="/assets/images/2013.02.02-rawbattery.jpg" alt="raw battery" /></p>
Three classic fixes for SMD PCB mishapsrxdtxd2013-02-02T00:00:00+02:00https://wemakethings.net/2013/02/02/classic_pcb_fix<p>Now, don’t tell me you’ve seen this one!..</p>
<p>After a long hiatus, I wanted to get back to electronics for a while. Finish <a href="/2012/04/09/dmx-dimmer-ready-for-testing">dmx-dimmer</a> and all. For warm-up, I decided to put together a <a href="/2012/10/04/catnip">CatNip kit</a> that <em>miceuz</em> gave me.</p>
<p>A few sloppy minutes later I was de-soldering one side of a <a href="http://en.wikipedia.org/wiki/Quad_Flat_Package">TQFP package</a> (ARM chip), which was placed on a bed of SMD paste and slipped a bit. It was all going well, then a trace flaked off the board. Oops.</p>
<p>No biggie, just solder in a thin wire. 0.1 mm will do just fine. It’s commonly available in the form of transformer refuse.</p>
<p><img src="/assets/images/2013.02.02-wire.jpg" alt="CatNip development board, with GPIO2.0 output connector wired-up directly to the microcontroller" /></p>
<p>I kept on soldering, listening to psytrance, minding my own business, when suddenly and for no apparent reason a 0603 resistor jumped right at me, and was gone the second after. Bad luck, it was 2 kΩ, and <strike>I didn't have any more of those on hand</strike> I was too lazy to look for one. I did have several 1 kΩ and a pin handy, so I hooked these up in series.</p>
<p><img src="/assets/images/2013.02.02-resistor_series.jpg" alt="Two SMD resistors standing vertically, connected by a clipped-off pin" /></p>
<p>After having populated most of the board, I noticed one resistor was still missing. 150 Ω, wasn’t in the kit. For demo purpose only, I decided to connect several larger-value resistors in parallel.</p>
<p><img src="/assets/images/2013.02.02-resistor_parallel.jpg" alt="Several SMD resistors stacked atop one another, don't get annoyed by the following line" /></p>
<p>What I did here, as you most probably see, is stack five 1 kΩ resistors atop one another. Could have gone with six, but this is just current limiting for a LED, so the same precise value is not strictly required.</p>
<p>Here’s the complete board before I rub it with acetone and glue the frankensteins:</p>
<p><img src="/assets/images/2013.02.02-result.jpg" alt="Resulting board, with all three quirks visible" /></p>
<p>Does it work? Well, it powers up and enumerates as USB storage, so I guess it does. No way to be sure, got no toolchain.</p>
<p>To give some context, here’s a lamp’s-eye view.</p>
<p><img src="/assets/images/2013.02.02-big_picture.jpg" alt="Big-picture shot of the workspace" /></p>
<p>That thing with a black/yellow handle? Unregulated 40 W noname, stock tip, China Export certified. The iron I was using. A close-up…</p>
<p><img src="/assets/images/2013.02.02-iron_tip.jpg" alt="Iron tip and SMD component comparison, a white smurf is seen lurking in the background over my Cortex" /></p>
<p>Why in the world?.. For fun mostly, so that I truly can.</p>
A wide-angle, low-pressure shower headpwfrxdtxd2013-01-30T00:00:00+02:00https://wemakethings.net/2013/01/30/shower_head<p>We wanted a shower head that doesn’t feel like you’re in the sink under the tap. We ordered one from DealExtreme, but it never arrived, and they didn’t return our calls. We shopped around, but they all cost like a washing machine.</p>
<p>Therefore this. Stainless steel, no filters, no frills. 16 cm wide, 188 1 mm holes. Four common HSS drill bits broke while doing the plate.</p>
<p>Smooth.</p>
<p><img src="/assets/images/2013.01.30-shower_head_front.jpg" alt="A wide shower head, front" /></p>
<p><img src="/assets/images/2013.01.30-shower_head_back.jpg" alt="A wide shower head, back" /></p>
<center><iframe width="420" height="315" src="https://www.youtube.com/embed/i9K286oTpJc" frameborder="0" allowfullscreen="yes">Wide shower head demo video, on YouTube.</iframe></center>
A moka pot stove from a clothing ironopit2013-01-24T00:00:00+02:00https://wemakethings.net/2013/01/24/moka-pot-stove-from-clothing-iron<p>I am a scientist, and I’m powered by coffee. The problem was, the only source of coffee at my venerable institution is a vending machine that spits back some brownish, watery Scheisse-coffee for 0.4 euro. Either that, or drinking coffee the Polish way, what will rot one’s stomach and soul eventually.</p>
<p>One way to build a stove is to go back to the basics and make the heating plate from nichrome wire, similar to what we did with the <a href="http://wemakethings.net/2012/04/01/cat-heater">cat heater</a>. After an evening spent with <em>ioch</em> calculating resistances and cross-sections I decided that handling 80m of wire is too much and went with <em>pwf’s</em> suggestion, that is, using a clothing iron. Such a stove wasn’t a new thing for us – we got the same idea from <a href="http://www.millionreasonswhylithuaniaisthebestcountryintheworld.com/lt/678/">some Lithuanian students</a>. Adapting a clothing iron makes perfect sense: it uses a kW or so, so it is quite efficient, the surface is non-sticky and it has inbuilt temperature control. Besides, who irons their clothes nowadays anyway?</p>
<p>One gloomy Sunday we went to a <a href="http://people.cs.uct.ac.za/~bfry/dseaward/insidestuff/wintermarket.html">Gibsonesque Turkish flea market</a> nearby and bought a spanking new clothing iron, made in GDR, for a few euros. I took it apart immediately – there weren’t much more than the heating plate with the heating element around it (seen here as the circular bulge between the rivets), the bi-metal plate that is probably the most basic temperature controller, a small lightbulb that we kept and the remnants of a temperature control wheel (you know, the silk-wool-cotton-linen sequence). The case is held together with the heating plate by the prominent screw. The plastic parts – the handle and such – were lost immediately so I can’t say anything about them.</p>
<p><img src="/assets/images/2013-01-24-breakdown.jpg" alt="The disassembled clothing iron" /></p>
<p>Since I have access to a ceramic kiln and several pounds of clay, it seemed a natural choice: clay is heat and water resistant, an insulator, easy to mold and clean. I used grainy (~2mm chamotte fraction) stoneware, as it’s cheap and contracts less than regular fine clay. All flat parts were rolled with an empty bottle, cut by hand and glued together with stoneware slip. This part of the process is hard to describe, so I’ll throw in a couple of pictures instead.</p>
<p><img src="/assets/images/2013-01-24-plate0.jpg" alt="The upper plate" />
<img src="/assets/images/2013-01-24-plate1.jpg" alt="The top plate with the triangular hole in it" />
<img src="/assets/images/2013-01-24-plate2.jpg" alt="The final structure: it has way too many support points, I should had stayed with three. On the other hand, some sanding and filing after the firing made things OK." /></p>
<p>I left it to dry for a few days, fired once at 960C, forgot about it, went to Israel, then glazed it one night and fired again up to 1020C.</p>
<p>The problem with ceramics is that the stoneware shrinks during the drying and firing. Nevertheless, this project was not a precision mechanics endeavour anyway – so we cut and drilled a metal plate and fastened it to the belly of the heating plate so that it looked horizontal and would not fall off.</p>
<p><img src="/assets/images/2013-01-24-fired-parts.jpg" alt="The fired piece" /></p>
<p><img src="/assets/images/2013-01-24-underbelly.jpg" alt="All in one, the cutting edge of low tech" /></p>
<p>I had made some nichrome loops inside, so we tied the cord in with some zip ties, checked if the tiny indication light was working and made a test run:</p>
<p><img src="/assets/images/2013-01-24-coffee-test0.jpg" alt="Waiting..." /></p>
<p><img src="/assets/images/2013-01-24-coffee-test1.jpg" alt="Here it goes" /></p>
<p>It takes about 2 minutes for this moka pot to boil. <em>ioch</em> and <em>pwf</em> already suggested adding an alarm clock w/ a relay to it, so that one’s coffee is ready after the first ‘snooze’. I’m also considering making a whale-shaped one, using a steam iron for some second degree burns.</p>
How to set up an open-source Stellaris Launchpad toolchain on Arch Linuxrxdtxdveox2012-12-30T00:00:00+02:00https://wemakethings.net/2012/12/30/stellaris_launchpad_on_arch_linux<p>We got some <a href="http://www.ti.com/ww/en/launchpad_site/stellaris.html">Stellaris</a> boards from Texas Instruments. Two each, of course. We put ‘em in the closet until the dev chain matures. After getting a nudge from <em>miceuz</em>, I finally decided to try it out. It turns out that setting up on Arch Linux has now become trivial.</p>
<p>There are many ways to get it working. I prefer open-source. The AUR is a total mess of <a href="https://aur.archlinux.org/packages.php?O=0&L=0&detail=1&C=0&K=eabi&SeB=nd&SB=n&SO=a&PP=30&do_Search=Go">EABI packages</a>. As per <a href="https://wiki.archlinux.org/index.php/Cross_Compiling_Tools_Package_Guidelines#Package_naming">cross-compiling tool guidelines</a>, the proper name for this toolchain is <code class="highlighter-rouge">arm-none-eabi</code> (if no vendor is specified). This name is taken by the <a href="http://www.mentor.com/embedded-software/sourcery-tools/sourcery-codebench/editions/lite-edition/">Sourcery CodeBench</a> stuff. Note also that it’s a binary redistribution.</p>
<p>Another set of packages (more widely adopted) is <code class="highlighter-rouge">cross-arm-none-eabi-*</code>. This is what I want. It is based on the <a href="https://github.com/esden/summon-arm-toolchain">summon-arm-toolchain script</a> and uses the GCC toolchain.</p>
<p>To debug, you will also need <a href="http://openocd.sourceforge.net/">OpenOCD</a>. To flash, <a href="https://github.com/utzig/lm4tools">lm4tools</a>. Create a few config files, and you are go.</p>
<p>So, the procedure.</p>
<ol>
<li>As a bare minimum, get the following from AUR: <code class="highlighter-rouge">cross-arm-none-eabi-gcc</code> <code class="highlighter-rouge">lm4flash-git</code>.</li>
<li>For debugging, also get these: <code class="highlighter-rouge">cross-arm-none-eabi-gdb</code> <code class="highlighter-rouge">openocd-git</code>. I asked <em>veox</em> to pack the latter. By the time you read this, the stable <code class="highlighter-rouge">openocd</code> from <code class="highlighter-rouge">community</code> will probably support Stellaris, so just use <code class="highlighter-rouge">pacman</code>. There is also <code class="highlighter-rouge">lmicdiusb-git</code>, but I haven’t tried that.</li>
<li>Add a <a href="http://kernelhacks.blogspot.com/2012/11/the-complete-tutorial-for-stellaris.html">udev rule</a>, so you don’t have to <code class="highlighter-rouge">sudo</code> all the time.</li>
<li><a href="http://scompoprojects.wordpress.com/2012/11/07/debugging-a-program-on-the-stellaris-launchpad-board/">Test your debugger</a>. As per the guide, I used <a href="https://github.com/scompo/stellaris-launchpad-template-gcc">stellaris-launchpad-template-gcc</a> to avoid obscure TI licenses.</li>
<li>Optionally, get the official <a href="http://www.ti.com/tool/sw-lm3s">StellarisWare</a> library. The page has broken JavaScript <em>and wants you to log in</em>, which I couldn’t. If you do manage to accompish this feat, know that you won’t be able to use their code for <em>anything</em> – just read the license. I propose we ditch it.</li>
</ol>
<p>Now just figure out why use this instead of <a href="/2012/10/04/catnip/">your usual workhorse</a>. Perhaps a <a href="http://www.fischl.de/arm/can_bus_interface_for_stellaris_launchpad/">CAN bus interface by Thomas Fischl</a>, the guy who gave us <a href="http://www.fischl.de/usbasp/">USBasp</a>?..</p>
Merry-go-round electronicsmiceuzpwf2012-12-08T00:00:00+02:00https://wemakethings.net/2012/12/08/merry-go-round-electronics<p>It’s an electronics part of merry-go-round saga. Read <a href="http://wemakethings.net/2012/12/06/merry-go-round">the first part about mechanics</a> before.</p>
<h1 id="the-task">The task</h1>
<p>When <em>pwf</em> asked me if I’d like to put some thought into this merry-go-round affair they were going to pull of, I didn’t hesitate much - the project was a good test of my electronics skills and my niggaz needed me - how could I refuse?</p>
<p>The task at hand was like this - the carousel hangs from a ceiling, it is driven by a variable frequency drive, there is a stage wheel beneath it which rotates, the carousel has to rotate together with the stage wheel in one mode and has to rotate fast (how fast is too fast?) in the other mode.</p>
<p>At first we were going to take readings from the shaft of the motor that drives the stage wheel (i’d even quickly made a tachometer from parts from a junk bin), but after inspection of all the mechanisms we understood that there was no chance - the age of the system approaches the years when people were walking on the Moon and it hasn’t seen much love from any caring engineer during all this time.</p>
<p>We decided to take the readings by attaching a rubber wheel with a rotary encoder to the steel bottom rim of the stage wheel - this way we could be sure that we get the exact measurements of movement of the edge of the stage wheel.</p>
<p>What about the carousel? We’ve chosen a variable frequency drive with a modbus option, so we could control it remotely, but what about the feedback? Luckily it came to me early enough in the process: we need a closed loop system for synchronization to work properly. It <em>might</em> have worked in the open loop mode, but the system was unknown, there was no time for testing, so <em>when in doubt - overengineer</em> - we’ll have another rotary encoder that’s reading the rotation of the carousel. This way we have a PID system that ensures that both the stage wheel and carousel have rotated exactly the same amount. Provided encoder readings correspond to a real rotation. Read on.</p>
<h1 id="reading-encoders">Reading encoders</h1>
<p>Ok, how do you transfer pulses from the encoder that might be up to 100m from the control panel? When in doubt… I’ve decided to use RS485 as a wire protocol for that. Quickly enough nice folks from Linear Technology and Maxim-ic have provided me with free engineering samples of receivers, drivers and transceivers. Far quicker than buying from distributors. And free.</p>
<p>We used a high-end encoder from <a href="http://metrology.precizika.lt/pdf/A58_EN.pdf">precizika</a>. Conveniently it was outputting a differential signal, so I’ve used <a href="http://www.maximintegrated.com/datasheet/index.mvp/id/1852">MAX3095</a> to read it and <a href="http://www.linear.com/product/LTC486">LTC486</a> to transmit it down the line.</p>
<p>I had time to take some nice pictures:</p>
<p><img src="/assets/images/2012.12.08-encoder-adapter1.jpg" alt="encoder adapter" />
<img src="/assets/images/2012.12.08-encoder-adapter2.jpg" alt="encoder adapter" /></p>
<p>But that’s boring. The fun part was designing all the protection - the thing was meant to be used in a theatre and things <em>do</em> get messed up in a theatre. The adapter uses the same RJ45 connectors for input and output, I know it’s a <em>BAD THING(tm)</em>, but those connectors were too convenient to not to use them, so I’ve had a nice afternoon designing a foolproof protection from reverse connections. And a fault indication.
<img src="/assets/images/2012.12.08-encoder-adapter-protection.png" alt="encoder adapter protection" />
It’s an encoder-side connector that usually <em>outputs</em> voltage. If the system sees voltage on 1 and 2 pins (this happens if you reverse connectors), the FUBLIA LED lights up and bad things do not happen.</p>
<p>Another fun part was developing an edge detector to blink some LEDs when pulses from the encoder are coming:
<img src="/assets/images/2012.12.08-encoder-adapter-edge-detector.png" alt="encoder adaptor edge detector" />
Note the extensive use of PNP transistors - I have a pile of them left after a project before, had to use ‘em up!</p>
<h1 id="control-unit">Control unit</h1>
<p>The control part is really boring, it’s just my <a href="http://wemakethings.net/2012/09/26/catnip/">CatNip</a> board with a special ‘kitteh’ - a ‘shield’ to condition RS485 signals, read some buttons and blink some LEDs. I’ve used <a href="http://www.linear.com/product/LTC488">LTC488</a> receiver to match the Linear Technology driver on the encoder adapter and <a href="http://www.linear.com/product/LTC485">LTC485</a> to talk to the variable frequency drive. I’ve written a of <a href="https://github.com/Miceuz/LPC1343CodeBase/blob/karusele/modbus.c">couple semi decent modbus functions</a>. The whole code is at my <a href="https://github.com/Miceuz/LPC1343CodeBase/tree/karusele">github repo</a>.</p>
<p>This is a picture of our control panel:</p>
<p><img src="/assets/images/2012.12.08-carousel-control.jpg" alt="control box" />
<img src="/assets/images/2012.12.08-carousel-control-internals.jpg" alt="control box inside" /></p>
<p>Well, all of this was a “clean room” design exercise - as the guys in the workshop were cutting and welding steel like real men, I had to emulate the unknown parts of the system. When I came to the workshop, the carousel was in rather early stages of being complete, so I had to spend some time writing utilities to graph step response, read on control systems theory and design a DMX LED dimmer while eating spacecake. I didn’t have an opportunity to run my system until the carousel, still hot from welding, was brought and installed in the destination place.</p>
<h1 id="the-motorized-plow">The Motorized Plow</h1>
<p>That’s where the fun started. My system worked quite well, but there was a problem with a stage wheel - the steel rim we were running our encoder wheel on was not that round after all. One fourth of the circle was squashed inside, so the carousel would go with the stage within the error of 10cm for 3/4 of the circle and run away in the last quarter. I could have thought of some trick in software, but because of sleep deprivation my skull was full of scrambled eggs instead of brains. So either you <em>solve optic problems with optics, mechanical with mechanics and electrical with electronics or you solve all the problems in software</em>. This time we went the former way - <em>pwf</em> added one more degree of freedom to the encoder wheel fixture, changed its angle and orientation on the rim and we were able to follow the wheel for two to three rotations within allowance of 20cm. Which was totally OK for our purposes, but it left a bad taste in my mouth. Check out <a href="http://wemakethings.net/2012/12/06/merry-go-round">the first part</a> for the crappy video of synchronization in action.</p>
<p>When I got up in the theatre (I’ve slept there, because I was too exhausted to go home), I was greeted by a flock of 50-year old males in formal suits - the theatre management. They brought an old man with them, who still works there as an electrician, but probably still remembers the times when men were walking on the Moon. This old man started telling me story about how he managed to build himself a motorized plow for his garden out of ropes and pulleys. Aha! That’s why stage wheel is in such a sorry state…</p>
<p>There is some pr0n to look at in the meantime:</p>
<p><img src="/assets/images/2012.12.08-carousel-vfd-pron.jpg" alt="VFD pr0n" /></p>
<p>Here you can see an AC induction motor, variable frequency drive for it, a reduction box with a chain to drive the carousel and a box that will hold electronics for a DMX LED dimmer.</p>
<h1 id="dmx-led-dimmer">DMX LED dimmer</h1>
<p>How long does it take to design and make a fully functional DMX LED dimmer? Two nights while eating spacecake to draw a PCB, one day to get the parts, etch and solder the boards and one day and one night to write firmware, test and install it.</p>
<p>As an optional bonus there had to be LED strips on the carousel, controllable via DMX. Well, how do you transfer power to a rotating thing? Ground goes through the frame, and live wire goes through a graphite brush on a slip ring. How much resistance/voltage drop do you get when the carousel rotates? Unknown. When in doubt… overengineer! We got this beefy transformer out of a trashed guitar amplifier, it was outputting 30V. And we hooked up a constant current source that would compensate for the voltage drop through the slip ring and bearings. And we made a nice 50W heater out of 4 parallel MOSFETs and a huge heatsink. But what if one of several LED strips is not connected? You get the same current pushed through the remaining ones of course. Hm.. no good, let’s put a PTC on every LED strip.</p>
<p>This is a constant current source:</p>
<p><img src="/assets/images/2012.12.08-dmx-led-power.png" alt="dmx dimmer current source" /></p>
<p>As for DMX part - it’s nothing fancy - just an AVR atmega8 hooked up via <a href="http://www.maximintegrated.com/datasheet/index.mvp/id/1852">MAX3095</a> to DMX line via an optocoupled open collector output to pull the gates of MOSFETs down via PWM.</p>
<p><img src="/assets/images/2012.12.08-dmx-led-pwm.png" alt="dmx led dimmer pwm" /></p>
<p>I used some <em>rxdtxd’s</em> <a href="https://github.com/rxdtxd/dmx-dimmer">DMX decoding code</a>. The whole thing is on github if someone is interested: <a href="https://github.com/Miceuz/DmxLedDimmerBasic">https://github.com/Miceuz/DmxLedDimmerBasic</a></p>
<p>PTC’s on the strips paid off nicely as one of those crap Chinese strips was shorting to the frame! Now just imagine all the things we said after discovering this at 5 o’clock in the morning!</p>
<h1 id="aftermath">Aftermath</h1>
<p>Well, it was a nice hell of a deathmarch involving a bunch of people, using a load of different skills and techniques. There was too much of things we didn’t know beforehand and no time to test ideas. Nevertheless, we are very lucky to have pulled this off. When in doubt… overengineer!</p>
Merry-go-roundrxdtxdpwfvarious artists2012-12-06T00:00:00+02:00https://wemakethings.net/2012/12/06/merry-go-round<h1 id="introduction">Introduction</h1>
<blockquote>
<p>Gotta get off, gotta get off, gotta get off of this merry-go-round…</p>
</blockquote>
<p>This is another big one, and it came in together with the <a href="/2012/11/18/chairs_on_rails/">rails</a>, so you can guess why there ain’t many pictures. We had our hands full of tools more labour-worthy than a camera.</p>
<p>Anyway, a <a href="http://en.wikipedia.org/wiki/Carousel">carousel</a> was to be made in <strike>little</strike> no time. It had to be 4 meters across. It had to spin, at various speeds. It had to sync with a revolving stage. It had to be stable enough during rotation that articles of fine modern furniture could be suspended from it.</p>
<p>My part in this was the rotating circle and its suspension to the axis. The rotor, in short.</p>
<h1 id="blueprints-what-blueprints-a-freecad-review">Blueprints? What blueprints? (A FreeCAD review)</h1>
<p>In short: there were none.</p>
<p>For all I intended to do, I really wanted some: we’re talking circles here, people! Lots of angles cut at precise lengths, and most of them in volume. But, alas, every artist is his own engineer.</p>
<p>I tried some open-source CAD programs, spending most time on <a href="http://free-cad.sourceforge.net/">FreeCAD</a> (version 0.12.5284), and the verdict is: not stage-ready.</p>
<p>First off, FreeCAD is a front-end with frills, written in Python 2 (and Qt). The back-end is <a href="http://www.opencascade.org/">OpenCascade</a>. There are big issues with both.</p>
<p>The biggest one with me is this. Since FreeCAD is written in Python (essentially a <em>prototyping</em> language, in my view), it breaks a lot. My system is probably quite different from that of the current developers’, and it dumped core once every three minutes (on average). Filing bug reports would have been useless: there were at least ten different exceptions in trace-backs, and we would have spent hours arguing whether this is a misconfiguration. Of Python.</p>
<p>If you do decide to try out FreeCAD, have the following in mind.</p>
<ol>
<li>
<p>Do <em>not</em> upgrade your real work parts to a combined part, upgrade copies instead and hide the originals. If you decide to edit the combined part later, exploding it will give you <strike>feces</strike> faces instead of solid objects.</p>
</li>
<li>
<p>Making a lot of copies at once might not copy everything, but it fills the object list anyway. Deleting objects that are listed but don’t exist drops core.</p>
</li>
<li>
<p>It seems there’s no way to specify an arbitrary reference axis when rotating, which caused me a lot of grief.</p>
</li>
<li>
<p>You either rotate in the current view’s plane, or one of pre-defined XY/XZ/YZ, which are also called top/front/side elsewhere. Confusing.</p>
</li>
<li>
<p>Rotating multiple objects in the same plane by a certain angle does not always result in them rotating the same angle. If it sounds wrong, that’s because it is.</p>
</li>
<li>
<p>Snapping uses algebraic units and doesn’t take the current view’s zoom level into account.</p>
</li>
<li>
<p>A lot of essential functionality is implemented as macros, which are not included in the basic package. <a href="http://sourceforge.net/apps/mediawiki/free-cad/index.php?title=Macro_Solid_Sweep">Solid Sweep</a> proves useful, if you can get used to it.</p>
</li>
<li>
<p>Boolean operations on solids do not always work, which is mentioned in <a href="http://sourceforge.net/apps/mediawiki/free-cad/index.php?title=FAQ#My_boolean_operations_fail.2C_or_give_weird_results">the FAQ</a>.</p>
</li>
<li>
<p>Also, they sometimes drop core.</p>
</li>
</ol>
<p>After several hours of cursing, I got this.</p>
<p><img src="/assets/images/2012.12.06-00-freecad-drawing.png" alt="Merry-go-round rotor in FreeCAD, partially" /></p>
<p>Which is, in my book, too long for too little. I eventually drew and calculated everything I <em>really</em> needed on paper.</p>
<p>Why not AutoCAD? Because I don’t use Windows. Why not Google SketchUp? Because that doesn’t have Boolean operations on solids in the freeware version. Why not DraftSight? Because that has very limited 3D functionality. Why open-source? Because we don’t really get anything but experience points for this.</p>
<p>Sorry for the long-wrought review, I just had it sitting in my home dir for three months. Back to the topic.</p>
<h1 id="a-slice-of-pi">A slice of Pi</h1>
<p>As soon as metal got into the shop, I set out to cut those beautiful long slender things into stacks of beautiful short identical things.</p>
<p>Remember, it’s a “circle” 4 meters across, made of short straight segments. A polygon, right. The circle’s perimeter is d * π = 4 π. We decided 24 corners is circular enough.</p>
<p>Technically, it was possible to take a square pipe blank and <a href="http://en.wikipedia.org/wiki/Metal_rolling">roll</a> it to achieve desired curvature, but we don’t have the equipment, and there were no resourses to order from a specialised shop.</p>
<p>As always, we designed it so that it could be taken apart (into four parts). This has a few advantages.</p>
<ol>
<li>
<p>It takes less space in the storage room when not needed. You don’t hang stuff you don’t need from a high ceiling, do you?..</p>
</li>
<li>
<p>It fits through the workshop’s door, and also into our painting chamber, in case we had time and paint to paint it (we didn’t).</p>
</li>
<li>
<p>Splitting the circle into four arcs that have a length of π is a nice inside joke. It lets us feel like we know what we’re doing.</p>
</li>
</ol>
<p>I then tack-welded these pieces into eight arcs, and tack-welded those parallel, in couples. It didn’t go too well. I made a jig to weld the short segments together into long arcs at a precise angle. The angle was good, but the jig was too short – it could only support three segments until the arc would start to curve due to its own weight. I set up a convoluted system of props to keep the dangling end from bending too much. This unwanted curvature was reduced somewhat, but still demanded an array of clamps to hold paired arcs together during welding.</p>
<p>Long story short: I was too lazy to set up one proper jig, and so had to set up two instead.</p>
<p><em>eggman</em> cut and drilled eight plates for segment connections. In the image below, you can see the four tack-welded segments, clamped together with the plates in between. The clamping was also needed for alignment. Luckily, it was just tack-welded, which allowed for fine adjustment (two holding and one adjusting with rebar). The hammer, fridge and van are for size reference.</p>
<p><img src="/assets/images/2012.12.06-01-circle-clamped.jpg" alt="Segments of the pie, clamped together on the floor" /></p>
<p>Most of it was rectangular profile, 30x15x1,5 mm. Pretty lightweight, and considerably more flexible along its 15 mm side compared to the 30 mm side. 6 pieces per arc, with end pieces slightly shorter than the middle ones, to accommodate the thickness of the connection assembly. The connection plates are just lengths of a wide strip, something like 5 or 6 mm thick. It will be slightly clearer from later images.</p>
<h1 id="suspension-lower-bearing-mount">Suspension: lower bearing mount</h1>
<p>The axis at the center had two machined bearing mounts, one at the top, one at the bottom. The circle connects to both with a total of 16 profiles (30x30x2 mm). We called them “strings”. 8 strings to the top, 8 to the bottom.</p>
<p>I started with the bottom mount, once again only tack-welding connection pates to the side.</p>
<p><img src="/assets/images/2012.12.06-02-lower-bearing.jpg" alt="Lower bearing mount, with string connection plates being welded to its side" /></p>
<p>There were holes for the bearing’s lid in the mount, which came handy for a kind of piggy-back-ride alignment job: screw on two alignment brackets, put a connection plate in the middle, tack, turn, repeat. It is hard to see in the image above, but there are also two pieces of metal, cut to the same length, held at the other side of the bearing mount with welding magnets. So the connection plate is right in the middle. It turned out later most of this wasn’t exactly necessary, and the connection plates could have been welded at the edge just as well.</p>
<p>I then put the bearing mount in the middle of the circle, cut four strings, with different angles at both ends, and welded plates with holes to those. Then four more strings, with yet another set of angles. It came together like this.</p>
<p><img src="/assets/images/2012.12.06-03-lower-bearing-mount-with-strings.jpg" alt="Circle connected to lower bearing mount with 8 strings, top-side view" /></p>
<p>What I leave out of the picture here is engineering: measuring the exact angles and lengths, taking the thickness of connecting pates and plane rotations into account, and all the running back and forth in between.</p>
<p>Four strings connect to the top of the circle at the middle of its segments, and four more connect to the bottom where segments meet.</p>
<p>What’s also different is we put in diagonals into the rectangles, to improve rigidity. It would have probably been even better if they were put in rotated 90 degrees along their own axes, so that the 30x15 profile’s flat side was co-planar with the circle’s imaginary cylinder. That would give rigidity in a plane tangent to said cylinder’s surface. But it would also mean we’d have to cut the ends of the diagonal profiles at two different angles, four times per diagonal, a total of 96 cuts. There was no time for that.</p>
<h1 id="inside-the-circles-angle">Inside the circle’s angle</h1>
<p>I must have been waiting for something, since I have many pictures of this stage.</p>
<p>Here’s another angle of the previous photo. It shows a closer view of all the connections mentioned thus far.</p>
<p><img src="/assets/images/2012.12.06-04-circle-side-view.jpg" alt="Circle connected to lower bearing mount with 8 strings, side view" /></p>
<p>Here’s how the pie segments connect:</p>
<p><img src="/assets/images/2012.12.06-05-circle-segments-connection.jpg" alt="Circle segments connection" /></p>
<p>Connection plates have three screws. This way, you can always take one screw out, and the other two will still be holding the thing together.</p>
<p>Also visible is one end of the lower string, screwed to the segment’s connection plate. Since a screw hole was available here, we thought it could as well be used for something other than just sticking two circle segments together.</p>
<p>It wasn’t so easy in the middle of the segments, where the other four strings go:</p>
<p><img src="/assets/images/2012.12.06-06-circle-string-top.jpg" alt="String connection to top of circle" /></p>
<p>An additional (thick) plate had to be welded to the (thin) profile here, and <em>inside the circle’s angle</em>. Took some fiddling, and I eventually settled on high-frequency pulse welding.</p>
<p>It all comes together at the bearing mount:</p>
<p><img src="/assets/images/2012.12.06-07-lower-bearing-mount-with-strings.jpg" alt="Lower bearing mount, with strings attached" /></p>
<p>There were also pieces of rod under the connection plates, to fill the gaps:</p>
<p><img src="/assets/images/2012.12.06-08-lbm-side.jpg" alt="Lower bearing mount, side view with connection plates" /></p>
<h1 id="stator-and-axis">Stator and axis</h1>
<p>What I was waiting for was for the stator and axis assembly to be finished. <em>pwf</em> did all of it, except for a few small parts I made while there was nothing else to do.</p>
<p>We initially planned the axis to be 2 meters high, but later settled on 1,5 m to reduce weight. This quickly proved to be the right choice, since the entire length could be reached from the floor. A shaky ladder was involved, sure, but only later on, during some final welding, and wasn’t required to hang the stator on a girder.</p>
<p>Anyway, here it is, upside down:</p>
<p><img src="/assets/images/2012.12.06-09-check-alignment-1.jpg" alt="Stator assembly" /></p>
<p>On the right is the motor and gearbox. On the left, the axis and upper bearing mount. The latter’s alignment is being checked.</p>
<p><img src="/assets/images/2012.12.06-10-check-alignment-2.jpg" alt="Upper bearing mount, checking alignment" /></p>
<p>In the measured plane, the maximum deviation was 0,032 mm.</p>
<p>I’ve also tacked four plates for strings to the upper mount by this point.</p>
<h1 id="death-march">Death march</h1>
<p>We were running out of time, so there are no more pictures of the build process. I’m also not sure what happened after what exactly.</p>
<p>What I do have on the hard drive is many pictures of couplers.</p>
<p><img src="/assets/images/2012.12.06-11-couplers.jpg" alt="Couplers and finished lower bearing mount" /></p>
<p>These would eventually be used in suspending the carousel. Can’t tell much about why and how many, since I had nothing to do with it. There were 16 of them, I think. I do remember <em>various artists</em> cutting machined cylinders lengthwise.</p>
<p>Also visible is the lower bearing mount, with plates welded all the way.</p>
<p>Fast-forward to a full assembly, past the night when everything that was tacked got welded.</p>
<p><img src="/assets/images/2012.12.06-12-mgr-lowered.jpg" alt="Merry go round, ready for lift-off" /></p>
<p>Eight more strings, to the upper bearing mount. Four of them straight, just as the lower ones. Four more at a tangent to the upper bearing mount, an almost 90° angle, because we thought this would be useful in rotation moment transfer. A few helical spirals would have been better, of course, but that would have been too much.</p>
<p>Several couplers are also visible. Well, almost. The hatched system of <a href="http://en.wikipedia.org/wiki/Batten_(theater)">battens</a> is required for weight distribution. When lifted, the merry-go-round’s rotation may introduce swinging, so the pipes have to be attached to a static structure with strip belts (one, orange, can be seen hanging in the image above).</p>
<p>Here it is again, in all its glare:</p>
<p><img src="/assets/images/2012.12.06-13-mgr-raised.jpg" alt="Merry go round, high in the sky" /></p>
<h1 id="whats-not-in-the-description">What’s not in the description</h1>
<p>Everything mechanical and <a href="/2012/12/08/merry-go-round-electronics/">electrical</a> – essentially rotation and synchronising with the revolving stage. Also, everything that got hung (a Styrofoam closet can be seen, though). I was not involved in those parts.</p>
<p>I did manage to get a few crappy videos, though.</p>
<p>First, stuffed animals spinning at half of maximum speed.</p>
<center><iframe width="420" height="315" src="https://www.youtube.com/embed/A3kV4P62szk" frameborder="0" allowfullscreen="yes">Washing machine drum coffee roaster (live run), on YouTube.</iframe></center>
<p>Second, rotation tracking. A stuffed flamingo is propped up on a box that stands on the stage, and suspended from a cord that is attached to the carousel at the same time.</p>
<center><iframe width="420" height="315" src="https://www.youtube.com/embed/4m1l4z-jkvo" frameborder="0" allowfullscreen="yes">Washing machine drum coffee roaster (live run), on YouTube.</iframe></center>
Chairs on rails, and other stuffrxdtxd2012-11-18T00:00:00+02:00https://wemakethings.net/2012/11/18/chairs_on_rails<p>I accidentally lost the habit of taking photos, which is an important accessory with cameras. So this isn’t going to be too concise.</p>
<p>Anyway, we’ve been up to this:</p>
<p><img src="/assets/images/2012.11.18-1_rails.jpg" alt="Rails, ready for welding" /></p>
<p>What is this blurry picture? It’s rails! (Ruby didn’t make it.) There are five segments like this one, 10 meters total. They connect with a simple <strike>pipe-walks-into-bar</strike> bar-goes-into-pipe joint. (No picture.)</p>
<p>As you might expect, the tolerance for rail-to-rail distance is really tight. One millimeter of deviation is near-disastrous. A manned chair rolls on top (as you might have guessed from the title), so it is imperative the thing be straight. To achieve that, we used precision-machined cylinders paired into guides.</p>
<p><img src="/assets/images/2012.11.18-2_rail_guides.jpg" alt="Rail guides for welding" /></p>
<p>The cylinders, alas, were not precise enough. A few let the pipe slide in just right, most had too small a hole, and one was being an ass altogether. I used files (a few) and sandpaper (lots) to make ‘em spec. It took half a day. You see, had any wobble been introduced, I’d have a big fat ring instead, and I don’t wear jewellery.</p>
<p>There were also other goofs with the machinist’s work, and that had to be worked around as well. (No picture.) This gave me a lot of time to think on various kinds of jobs and how you naturally expect a certain degree of precision, how big a millimeter really is, and stuff.</p>
<p>Anyway, making four guides with the same rail-to-rail distance was not exactly hard once I had the cylinders. A few clamps and a few magnets, basically (no picture).</p>
<p>The guides are then put on a pair of awry rails and straighten those out. If you’re wondering, the cross section looks like this:</p>
<p><img src="/assets/images/2012.11.18-3_rail_cross_section.jpg" alt="Rail cross section: a pipe welded onto a T-bar" /></p>
<p>I used the same cylinders mentioned above, before they became paired guides, to weld a pipe to a T-bar.</p>
<p>With the rails aligned and the section’s diagonals measured, I put <a href="http://en.wikipedia.org/wiki/Track_(rail_transport)">sleepers</a> on top. The guides are cut in two and removed.</p>
<p>Repeat five times, have a little fun in the workshop. Repeat a hundred times, start a mining operation.</p>
<p>Oh, there were also two contraptions where the railroad ends, to stop incoming locomotives. (No picture.) A little piece of it, though, aligned for welding:</p>
<p><img src="/assets/images/2012.11.18-4_rail_stop_align.jpg" alt="Rail stop piece alignment" /></p>
<p>The final thing, cropped for image size (again, Ruby didn’t make it):</p>
<p><img src="/assets/images/2012.11.18-5_chair_on_rails.jpg" alt="Rail stop piece alignment" /></p>
<p>I didn’t do the chairs, so there’s not a lot I can write about them, except that they roll on four wheels, have eight additional bearings for alignment, and have been deemed safe for use in long-distance travel.</p>
<h1 id="gear-review">Gear review</h1>
<p>Working at the railroad was not the true reason we did this project. At the end of the day, it all boils down to how my gloves do in the workshop.</p>
<p><img src="/assets/images/2012.11.18-8_guide_gloves.jpg" alt="Guide 5005, new and used" /></p>
<p>On the left is a pair of brand-new, never-before-used Guide gloves, model 5005. On the right, a pair of same gloves, two months into regular hard work. From experience, this is a month into posthumous life.</p>
<p>If you asked me, these are good enough for general metalwork. I think the box said the palm side is synthetic leather and covered in Teflon. I’ve literally soaked them in oil twice (during drilling) and they didn’t turn into stone (as natural leather tends to).</p>
<p>To the touch, they’re pretty thin, so they won’t do at the wood shop, but they hold up reasonably well otherwise. Those holes on the knuckles are from grinder sparks (the backhand is, of course, nylon or polyester or something like that). The holes on the fingers are from turning tight screws, so these won’t do in the auto shop, either.</p>
<p>I’ve done quite some welding with these gloves, too. A thing I learned is they let heat through, to the point where I got light burns on my palms, but the gloves themselves didn’t burn or shrink (as, again, natural leather would).</p>
<p>Another weird thing is they are lightly metallic. Put these on, and you’re a magnet magnet!..</p>
<p>P.S. If you’re a Guide representative, please send various models from your catalogue in our general direction. Size 9. Thank you.</p>
A simple car battery chargerrxdtxd2012-11-13T00:00:00+02:00https://wemakethings.net/2012/11/13/a_simple_car_battery_charger<p><img src="/assets/images/2012.11.14-auto_battery_charger.jpg" alt="Lead-acid battery charger" /></p>
<p>This is about making a very simple charger for lead-acid batteries, commonly used in automobiles.</p>
<p>In case you can’t parse the picture, the setup is simple: mains power is connected to a <a href="http://en.wikipedia.org/wiki/Autotransformer">variable autotransformer</a>, then in series to a transformer, a <a href="http://en.wikipedia.org/wiki/Diode_bridge">diode bridge</a>, an ammeter (not visible in the picture), and a battery. There are also capacitors and a voltmeter in parallel with the bridge’s output.</p>
<p>The purpose of each block is as follows:</p>
<ul>
<li>the autotransformer is used to regulate voltage and current, simultaneously;</li>
<li>the transformer drops voltage;</li>
<li>the diode bridge rectifies AC;</li>
<li>capacitors smooth out the rectified waveform;</li>
<li>the ammeter and voltmeter are for monitoring;</li>
<li>the battery is the load.</li>
</ul>
<p>I have no idea whatsoever what the exact parameters of each block are, except that most of them are big.</p>
<p>Both transformers’ wire windings should be thick enough to withstand the current pumped through them.</p>
<p>The step-down transformer should have a ratio such that it can drop mains voltage to a value slightly above the desired output voltage. This accounts for the voltage drop on the bridge and the fact that to charge a battery in reasonable time, a higher than rated voltage has to be applied.</p>
<p>My diode bridge here is four individual diodes whose ratings are certainly overkill for the task. Voltage drop on the bridge is twice the drop on a single diode.</p>
<p>The caps are rated for 400V – that’s what I found in the bin. They can surely be quite smaller, but at least twice the maximum voltage.</p>
<p>The ammeter was also available in the bin. It’s analog, with a dial and a maximum value of 10 A. If you intend to use a multimeter as an ammeter, know that they might not have the appropriate circuitry inside, even if it’s on the dial. Also, there might be a cigarette butt instead of a fuse if a friend of yours blows it and decides to play a prank on you.</p>
<p>The voltmeter is an el-cheapo multimeter from the store. (EDIT: I eventually swapped that out for an analog voltmeter, so the multimeter could be used elsewhere.) Its range should be bigger than the charger’s maximum output voltage.</p>
<p>In desperate times, all of this can be done with just a voltage-down transformer and a diode bridge. Everything else is optional, if you’re careful. Otherwise, you’ll zap batteries, since 1925:</p>
<p><img src="/assets/images/2012.11.14-zap_batteries.jpg" alt="Zap batteries!" /></p>
<p>If a transformer’s winding is too thin (say, less than 1 mm<sup>2</sup> with 5 amps DC on the output), you’ll fry it:</p>
<p><img src="/assets/images/2012.11.14-burnt.jpg" alt="Fry transformers!" /></p>
<p>On a whole different note: is this all we’ve been up to last month? A makeshift car battery charger?.. Of course not.</p>
<p>What was it? Well, tune up your internet receivers, it’s <a href="/2012/11/18/chairs_on_rails/">coming soon</a>!</p>
CatNip ADC performance measurementmiceuz2012-10-12T00:00:00+03:00https://wemakethings.net/2012/10/12/catnip-adc<p>I’ve quickly measured ADC performance by putting a 2 x 10K voltage divider into ADC0 and taking 64K samples. This by no means is a proper test, but let the images speak for themselves.</p>
<p>ADC performance of Microbuilder’s design on a board fabricated by us before:<img src="/assets/images/2012.10.12-adc-microbuilder.png" alt="ADC performance Microbuilder" /></p>
<p>ADC performance of [CatNip][CatNip]:<img src="/assets/images/2012.10.12-adc-catnip.png" alt="ADC performance CatNip" /></p>
<p>Here is the histogram comparison:<img src="/assets/images/2012.10.12-adc-histogram.png" alt="ADC performance CatNip" /></p>
<p>It seams, the effort I put while routing ADC traces is paying off…
[CatNip]:http://wemakethings.net/2012/10/04/catnip</p>
CatNip - LPC1343 development boardmiceuz2012-10-04T00:00:00+03:00https://wemakethings.net/2012/10/04/catnip<p>Roughly a year ago we have <a href="http://wemakethings.net/2012/01/17/modifying-the-lpc1343-devboard/">expressed our interest</a> in ARM based micro controllers and a concern in shortage of devboards of these to order. After doing a couple of projects on our <a href="http://wemakethings.net/2012/02/02/lpc1343-devboard-continued/">cheapo-pro</a> made boards I’ve stumbled on lack of some features I want and I ran out of my boards. I wanted an ARM devboard tailored for my purposes. So, what does one do in such circumstances in our open hardware world of freedom? Roll your own of course! After a week long routing and 5 months wait for the customs and post offices to resolve &#279; in my name, today I’ve accidentally met the postman and saved myself a trip to a post office:</p>
<p><img src="/assets/images/2012.10.04-catnip_board.jpg" alt="CatNip" /></p>
<p>So, the devboard is based on <a href="http://www.microbuilder.eu/projects/LPC1343ReferenceDesign/">LPC1343 Reference Design</a> by Microbuilder and the main differences are:</p>
<ul>
<li>USB connection header is added in order to facilitate adding an external case mounted USB connector that is placed far away from the board</li>
<li>RESET pin is in a breakout in order to allow putting a reset button on the device case</li>
<li>non-usb power is connected via screw terminals</li>
<li>eeprom in SO8 package is used as it’s more common</li>
<li>separate power header is added to export regulated and incoming voltages to daughter boards</li>
<li>most of 3.3 V and GND connections removed from breakout as it encourages ground loops, GND connections are left near communication pins (SPI, I2C, RXTX) for easier prototyping, 3.3 V connection is left near ADC inputs as it’s handy to limit ADC input to 3.3 V by adding a diode</li>
<li>all UART pins except RX and TX are reclaimed for other purposes</li>
<li>more ADC pins added</li>
<li>onboard LED pin is added to header</li>
<li>JTAG connector removed and it’s pins reclaimed for GPIO/ADC (I don’t have a JTAG programmer currently)</li>
<li>an effort has been made to not to route digital lines under ADC lines in order to achieve ADC performance that <a href="http://wemakethings.net/2012/10/12/catnip-adc/">sucks less</a></li>
</ul>
<p>I wanted myself a board that I could use in projects I do and leave it there, the board should be big enough to support expansion “shields” and it had to be easy to put the board into random box that has all connectors mounted - I didn’t like the idea of exposing on-board mini-USB connector to hostile outside world, neither I liked the idea of 2.5mm power jack. I like to connect analog and digital grounds at power supply, hence the single power export to daughter boards.</p>
<p>The eagle files are available on my github: <a href="https://github.com/Miceuz/CatNip">https://github.com/Miceuz/CatNip</a>. The board is compatible with original <a href="https://github.com/microbuilder/LPC1343CodeBase">firmware library by Microbuilder</a>, but you also can check my own fork: <a href="https://github.com/Miceuz/LPC1343CodeBase]">https://github.com/Miceuz/LPC1343CodeBase</a></p>
<p>In general, what I like most about this design is that LPC1343 micro has USB 2.0 hardware inside and together with eeprom chip onboard, it let’s you perform configuration of your device “in the field”. Microbuilder has started a good initiative by writing an easy and flexible command line framework, so a standard blinky example comes with a command line interface that you can access by virtual serial port. I’m working on adding various peripheral functions like ADC, SPI, PWM, I2C to the command line so it has some resemblance to bus pirate for free. Another thing - it has internal boot loader by NXP, that makes the chip to appear as a mass storage device in programming mode - you just copy your new firmware and reset the chip - no external programmer hardware is required. On compiling side - GNU development environment is available. Oh, BTW, did I mention that you can find LPC1343 for cheaper than ATMEGA328?</p>
<p>I have parts and PCBs for 10 boards and currently have no intention to sell them. The price I was able to achieve is $12.20 per board on this small run, so if someone would like to get one for $25 or so, ping me or get ir from <a href="https://tindie.com/miceuz/lpc1343-arm-devboard/">tindie.com</a>, I might do another run. But you can hardly beat TI stellaris launchpad for five bucks and free shipping…</p>
Capacitance measurement using low pass filtermiceuz2012-09-26T00:00:00+03:00https://wemakethings.net/2012/09/26/capacitance_measurement<p>Update 2012-11-30 <strong>A new working vesion of <a href="http://wemakethings.net/chirp">plant watering alarm</a> is available for sale! It’s open source and it goes <a href="http://wemakethings.net/chirp">Chirp!</a></strong></p>
<p>So I’m building the new version of my <a href="http://wemakethings.net/2012/06/21/plant_watering_alarm">Plant Watering Alarm</a>. I’m doing it based on capacitive humidity sensing - damp soil acts as an electrolyte increasing the capacitance of some makeshift capacitor made of couple of traces on PCB. I’m currently just counting amount of processor ticks while charging the capacitor till 0.63Vcc and it’s working quite OK, but a few days ago I have stumbled on this technique to measure capacitance:</p>
<p><img src="/assets/images/2012.09.26-capacitance_measurement_idea.png" alt="Capacitance measurement idea" /></p>
<p>Idea is straight forward - you feed square wave into low pass filter composed of a resistor and your probe as capacitor C1. As capacitance of C1 changes, so does cut off frequency of this low pass filter, lowering the peaks of output waveform, then this kinda-triangular waveform is rectified by a diode D1 and a capacitor C2 to give voltage estimation of capacitance of C1. Here you can see an approximation of what I saw on my shabby analog scope:</p>
<p><img src="/assets/images/2012.09.26-triangular_wave_plot.png" alt="Filter output" /></p>
<p>I’ve instantly put together a circuit using 555 timer to generate a square wave. While playing with the circuit I’ve noticed that when I increase C1 or R1, peak values do not go lower linearly, then I’ve noticed, that capacitor does not discharge fully as square wave is exactly 50% - so the peak-to-peak value is changing, not zero-to-peak. This creates some problems as voltage on the rectified output would not swing as much as it could, we are loosing dynamic range…</p>
<p>The fix was easy - just discharge C1 on zero phase of square wave. You could use a PNP transistor for that:</p>
<p><img src="/assets/images/2012.09.26-capacitance_measurement_pnp.png" alt="Add a PNP transistor" /></p>
<p>It looked much better on the scope, but there is one slight problem - emitter-base junction will conduct until there is more than 0.7V difference between them. So, I’m left with constant 0.7V on C1 after each charge/discharge cycle. Ok, lets use two transistors:</p>
<p><img src="/assets/images/2012.09.26-capacitance_measurement_npn.png" alt="Proper way to discharge this cap" /></p>
<p>Q3 acts as a logic NOT component outputting HIGH, when the square wave goes LOW - this turns Q2 on really hard and capacitor discharges until it reaches Vce of the transistor which is much lower than 0.7V. OK, so far so good, I can go on with calculations: <strong>what is the most optimal value for R1 so I would have the biggest voltage swing in my capacitance range?</strong> Here comes The Formula (taken from the great <a href="http://www.electronics-tutorials.ws/rc/rc_1.html">Electronics Tutorial about the RC Time Constant</a>):</p>
<p><img src="/assets/images/2012.09.26-the_formula.png" alt="The Formula" /></p>
<p>Vc is voltage across capacitor, Vs is square wave HIGH voltage, t is time, R and C are resistance and capacitance of your RC network. OK, lets <a href="http://www.wolframalpha.com/share/clip?f=d41d8cd98f00b204e9800998ecf8427ecrdgbr1joh">put it</a> into Wolframalpha:</p>
<p><img src="/assets/images/2012.09.26-WolframAlpha--3__1_-_e-162510-94152C_C710-12_to_4210-12--2012-09-26_1702.png" alt="8mhz 4.1K" /></p>
<p>This is a graph of Vc for t=62.5ns, R=4.1K and capacitance from 7pF to 42pF as this is my current probe capacitance range when in air and when fully submersed in water. Not too linear, but oh well, tradeoffs must be made.</p>
<p>I know 4.1K is optimal because of <a href="http://www.wolframalpha.com/share/clip?f=d41d8cd98f00b204e9800998ecf8427ebdqno2m8mv">this graph</a>:</p>
<p><img src="/assets/images/2012.09.26-WolframAlpha--plot_3__1_-_e-62510-9R710-12_-_3__1_-_e-162510-9R4210-12_R_100_to_8000--2012-09-26_1406.png" alt="deltaV" /></p>
<p>On Y axis there is a voltage difference between points at 7pF and 42pF and on X axis is resistance of R1. Heck, I can calculate that <a href="http://www.wolframalpha.com/share/clip?f=d41d8cd98f00b204e9800998ecf8427e1sauhq2cg8">precisely</a>:</p>
<p><img src="/assets/images/2012.09.26-maximize.png" alt="Exact value for R1" /></p>
<p>So, optimal value for R1 is 4.1K and voltage swing is from 2.66V to 1.57 minus the diode drop. The response is not linear, so R1 could be chosen smaller so the graph would shift to more linear region or it can be handled in software.</p>
<p>On final note, I’m yet to build a prototype based on this technique. I’m not sure if all of this will go into Plant Watering Alarm as it’s working quite ok in its current iteration. 1.75V is 1.74/(3V/1024)=596 values on Attiny44 10 bit ADC, it could be improved by adding an external voltage reference or doing some op-amp shifting/scaling kung fu, but it’s not really feasible for such a simple device as Plant Watering Alarm is ment to be. Maybe I will get on building a high end soil moisture probe, so let me know if you would be interested in that.</p>
<p>Meanwhile here’s a sneak peak preview of current iteration of Plant Watering Alarm:</p>
<p><img src="/assets/images/2012.09.26-plant_watering_alarm.jpg" alt="plant watering alarm" /></p>
Phono preamp as a first electronics projectmiceuz2012-09-21T00:00:00+03:00https://wemakethings.net/2012/09/21/phono_preamp<p><em>Mr. Hat</em> contacted me asking for a help in building a phono preamp for his vinyl record player that he recovered from oblivion somewhere.</p>
<p>As you probably know, there are some issues with vinyl records that require audio tracks to be mastered in certain way before they are put into a disc. Particularly, you have to attenuate low frequencies, so that the needle won’t jump between tracks when that kick drum is really delivering, and you have to amplify high frequencies so that they rise above the noise floor. When you want to play a record back, you have to reverse this process - amplify lows and attenuate highs - that’s why you need a phono preamplifier.</p>
<p><em>Mr. Hat</em> has chosen <a href="http://www.recordingmag.com/resources/resourceDetail/319.html">this design</a> for his build. There are lots of other phono preamp designs that have a potential to be better, but I’ve told him to simmer down - when you are building your First Project, you want results and you want them fast. So I skipped on all that fancy unobtanium audio purposed polystyrene capacitors and designed in simple plain ceramics with horrible tolerances that I believe will make real audiophiles turn blue. I’ve etched a couple PCBs so he wouldn’t need to make a mess on a protoboard.</p>
<p><img src="/assets/images/2012.09.21-phono_preamp_schematics.jpg" alt="Phono preamp schematics" /></p>
<p>This was my first attempt at designing for success from the first try and I’ve failed miserably in designing a two rail power supply. At first the footprint for bridge rectifier was wrong, then I’ve discovered that pinouts for LM79XX parts differ from LM78XX. Yeah, never assume anything and double check the pinout ant footprint. The power supply turned out as retarded as it can go - when cutting traces to fix the LM79XX pinout I’ve cut the wrong traces! Later i’ve discovered that LM79XX parts need more capacitance on the output than LM78XX, as negative rail was oscillating like hell!</p>
<p><img src="/assets/images/2012.09.21-phono_power.jpg" alt="Retarded power supply" /></p>
<p><img src="/assets/images/2012.09.21-phono_power_schematics.jpg" alt="Not so good split power supply" /></p>
<p>And finally, relaying on this design for two rail power supply is just dumb as output tolerances for LM78XX and LM79XX are 2% to 4% when you get them from reliable manufacturer, in other words, you won’t have you rail voltages to be equal unless you handpick the matching parts. I’d better just put a 24V linear regulator, split its output via 1% tolerance resistors and buffered that with op-amp.</p>
<p>I made <em>Mr. Hat</em> to solder his first project in SMD and he managed it ok, but goofed up the wires horribly.</p>
<p><img src="/assets/images/2012.09.21-phono_preamp.jpg" alt="First time SMD soldering" /></p>
<p>Later he made an enclosure from copper clad board.</p>
<p><img src="/assets/images/2012.09.21-phono_case.jpg" alt="Phono preamp in a box" /></p>
<p>It didn’t work on the first try - <em>Mr. Hat</em> had messed up some mechanics in a turntable and outputs were shorted, but after some poking with multimeter and a little bit of common sense, we have found a part that was upside down. After dealing with that, we’ve heard that special popping sound of vinyl and the first chords - the eyes of <em>Mr. Hat</em> were glowing and the mouth had that sleazy smile - it works!</p>
<p>If someone is interested in ready made Eagle files, you can get them form my github repository: <a href="https://github.com/Miceuz/PhonoPreamp">https://github.com/Miceuz/PhonoPreamp</a> (power bugs were fixed)</p>
Bus Pirate and random plasma TV indicatorrxdtxdmiceuz2012-08-20T00:00:00+03:00https://wemakethings.net/2012/08/20/bus_pirate_and_random_plasma_tv_indicator<p>We found a plasma TV by the dumpster. Lots of neat stuff inside. Say, this here 6-LED indicator with a M62320FP chip, an I/O port expander for I2C. Not to mention all the aluminum…</p>
<p><img src="/assets/images/2012.08.20-bus_pirate.jpg" alt="Bus Pirate v3.5" /></p>
<p><img src="/assets/images/2012.08.20-indicator.jpg" alt="6 LEDs, one I2C demultiplexer" /></p>
<p>Very conveniently, BP has a BASIC interpreter, enough to goof around.</p>
<figure class="highlight"><pre><code class="language-vb" data-lang="vb"><span class="mi">10</span> <span class="c1">REM PROGRESSBAR</span>
<span class="mi">20</span> <span class="n">LET</span> <span class="n">A</span><span class="o">=</span><span class="mi">116</span>
<span class="mi">30</span> <span class="n">LET</span> <span class="n">M</span><span class="o">=</span><span class="mi">255</span>
<span class="mi">40</span> <span class="n">LET</span> <span class="n">V</span><span class="o">=</span><span class="mi">63</span>
<span class="mi">50</span> <span class="n">START</span>
<span class="mi">60</span> <span class="n">SEND</span> <span class="n">A</span>
<span class="mi">70</span> <span class="n">SEND</span> <span class="n">M</span>
<span class="mi">80</span> <span class="n">SEND</span> <span class="n">V</span>
<span class="mi">90</span> <span class="n">STOP</span>
<span class="mi">100</span> <span class="n">DELAY</span> <span class="mi">500</span>
<span class="mi">120</span> <span class="c1">REM IF V=0 THEN GOTO 150</span>
<span class="mi">121</span> <span class="n">IF</span> <span class="n">V</span><span class="o">=</span><span class="mi">0</span> <span class="n">THEN</span> <span class="n">LET</span> <span class="n">V</span><span class="o">=</span><span class="mi">127</span>
<span class="mi">125</span> <span class="n">LET</span> <span class="n">V</span><span class="o">=</span><span class="n">V</span><span class="o">/</span><span class="mi">2</span>
<span class="mi">130</span> <span class="n">GOTO</span> <span class="mi">50</span>
<span class="mi">150</span> <span class="n">END</span></code></pre></figure>
<p>Should have made a cylon, yeah.</p>
Drum coffee roaster, completerxdtxd2012-07-27T00:00:00+03:00https://wemakethings.net/2012/07/27/coffee_roaster_complete<p>We are almost out of coffee again, so <a href="/2012/07/14/coffee_roaster_revisited/">the fixed roaster</a> is going for a hot run. On a sunny day, we took our green beans, 4,5 kg this time, and went outside the workshop.</p>
<p>The setup consists of the roaster itself, a propane gas stove, an electricity extension cord for the motor, and a big pan to rapidly cool the beans when they’re done (to prevent overroasting).</p>
<p>One can spin the pan and submerge it in water, exactly what we did on our <a href="/2012/07/04/coffee_roaster/">first attempt</a>. This time, though, the pan is made of cast iron (heavy). So instead, we used a compressed air gun.</p>
<p>There was also a chess table and refreshments, so we could do something while we do nothing.</p>
<p>We started off by putting a batch of green beans in, 1,5 kg at a time. I’m sure it could take more, but we didn’t know the dynamics yet.</p>
<p><img src="/assets/images/2012.07.27-green_coffee_beans_in_roaster.jpg" alt="Space monkeys, ready to be shot into space" /></p>
<p>And the dynamics, I must tell you, are quite something.</p>
<p>The first batch took us something like 90 minutes – on a steady fire that was probably too low. The roast is moderate to medium light, according to <a href="https://en.wikipedia.org/wiki/Coffee_roasting#Degree_of_roast_pictorial">this</a>.</p>
<p>The second batch saw a lot more fiddling with the fire. A miniscule turn on the stove’s handle, and the beans go from moderate light to Spanish black in a matter of minutes. There was also a lot of smoke, but nothing a compressor-powered air gun can’t handle.</p>
<p>The third went a lot smoother. We had a handfull of roasted beans from our previous trials, a reference colour to aim for. It still took quite long, almost an hour, since we didn’t want to screw up the last batch. And it was an hour of playing chess, watching a drum spin, which beats anything.</p>
<p>After a batch is done in the roaster, we dump it in our pan and cool it.</p>
<p><img src="/assets/images/2012.07.27-grade4.jpg" alt="Roasted coffee beans in a pan" /></p>
<p>Then it goes into an airtight container. In the image below, left to right: batches 1, 3, 2.</p>
<p><img src="/assets/images/2012.07.27-coffee_grades.jpg" alt="Roasted coffee beans in airtight containers" /></p>
<p>Here’s a short video of the process.</p>
<center><iframe width="420" height="315" src="https://www.youtube.com/embed/YDnRKhIKVdw" frameborder="0" allowfullscreen="yes">Washing machine drum coffee roaster (live run), on YouTube.</iframe></center>
Upgrade boot process from BIOS+MBR+GRUB to UEFI+GPT+GRUB2 in Arch Linuxveox2012-07-23T00:00:00+03:00https://wemakethings.net/2012/07/23/mbr-to-uefi<p>I have a 64-bit system running Arch Linux. MBR and its extended partition is a PITA. I’ve been using GRUB-Legacy far too long to see its limitations. <a href="https://www.archlinux.org/news/grub-legacy-no-longer-supported/">Official support was recently dropped</a>. So now is a good time to update from both in one go.</p>
<p>This is my log of how I did it. It worked for me, it might not work for you. I omit the details and specific commands and provide source links instead. Have a general understanding of what you are doing. If you do not need/want UEFI, or GPT, or GRUB2, if you don’t see the benefits of either, or if you not know what <code class="highlighter-rouge">modprobe</code> does, this “guide” is not for you.</p>
<p>Read the entire post before you do anything.</p>
<ol>
<li>Make full system backup.</li>
<li>Make rescue media. I have <a href="http://gparted.sourceforge.net/livecd.php/">GParted Live</a>, <a href="http://www.sysresccd.org/SystemRescueCd_Homepage">SystemRescueCD</a>, <a href="https://wiki.archlinux.org/index.php/Archboot">Archboot</a>, <a href="http://www.linuxmint.com/download.php">Linux Mint</a> and <a href="http://www.ubuntu.com/download">Ubuntu</a>. Get your own and learn to use it.</li>
<li>Edit partition table. Make space for a <a href="https://wiki.archlinux.org/index.php/UEFI">UEFISYS partition</a>, leave space at the beginning and end of hard drive for the <a href="https://wiki.archlinux.org/index.php/GUID_Partition_Table">GPT</a>.</li>
<li><a href="https://wiki.archlinux.org/index.php/Grub#Backup_Important_Data">Backup MBR</a>. Also, copy this backup to external backup media.</li>
<li>Reboot, enable EFI and see if you can boot. If so, you’re good to go. If not, reboot in BIOS mode. Continue at your own risk. You will have to use GRUB rescue mode later.</li>
<li><code class="highlighter-rouge">modprobe efivars</code> to enable <code class="highlighter-rouge">efibootmgr</code> operation. If <code class="highlighter-rouge">/sys/firmware/efi</code> is populated, you’re good to go. If not, continue at your own risk. You will have to use GRUB rescue mode later.</li>
<li><a href="https://wiki.archlinux.org/index.php/GUID_Partition_Table#Convert_from_MBR_to_GPT">Convert from MBR to GPT</a>.</li>
<li><a href="https://wiki.archlinux.org/index.php/UEFI#Create_an_UEFI_System_Partition_in_Linux">Create the UEFISYS partition</a>.</li>
<li><a href="https://wiki.archlinux.org/index.php/Grub#Backup_Important_Data">Backup GRUB-Legacy</a>.</li>
<li><a href="https://wiki.archlinux.org/index.php/Grub#UEFI_systems_2">Install <code class="highlighter-rouge">grub-efi-x86_64</code></a>.</li>
<li>If <code class="highlighter-rouge">'modprobe efivars'</code> worked previously, you’re more or less done.</li>
</ol>
<p>If it didn’t work, <code class="highlighter-rouge">'grub-install'</code> will fail with</p>
<div class="highlighter-rouge"><pre class="highlight"><code>Fatal: Couldn't open either sysfs or procfs directories for accessing EFI variables.
</code></pre>
</div>
<p>After all, it’s still booted in BIOS mode without UEFI.</p>
<ol>
<li>Reboot, enter UEFI menu and boot through <a href="https://bbs.archlinux.org/viewtopic.php?id=85603">GRUB2 rescue mode</a>.</li>
<li><a href="https://wiki.archlinux.org/index.php/Grub#Install_grub-uefi_boot_files">Reinstall <code class="highlighter-rouge">grub-uefi</code> boot files</a>.</li>
<li>Break open the champagne. If not, set yourself on fire and run in circles.</li>
</ol>
Drum coffee roaster, revisitedrxdtxd2012-07-14T00:00:00+03:00https://wemakethings.net/2012/07/14/coffee_roaster_revisited<h1 id="manual-mode-trials">Manual mode trials</h1>
<p>My <a href="/2012/07/04/coffee_roaster/">previous attempts at mechanising coffee bean roasting</a> were unsuccessful, so I slapped on a handle to rotate the drum manually.</p>
<p>It worked pretty well until I noticed something odd: beans started falling out of the drum, like if there was a hole big enough. I know there weren’t any, at least until I hadn’t put a gas stove under the drum.</p>
<p>Turned out the doors of the drum were attached to its frame with plastic. Plastic! It wouldn’t melt at the measly 90°C inside a washing machine. But it did in my case.</p>
<p>So I took the doors out and continued with the operation, now rocking the handle back and forth at an appropriate speed, so the beans would keep roasting. I later used a propane torch to burn all the plastic out, then washed the drum with water to remove any residue.</p>
<p>It became evident at this point that the 2 RPM motor I intended to use previously would have been too slow, and my coffee would have burned. So fortunate it didn’t work.</p>
<p>Besides all that, it actually requires two people for this mode of operation: one rocking the handle, and one checking if the beans are done, taking a small batch of them out with a spoon and comparing color to the reference.</p>
<p>If I had to continue with the roaster like this, I would have turned those four big screws by the doors around, so they would act as stops, bumping into those “ribs” that hold the device together, preventing the hole which was previously a door from pointing downwards and dumping all the beans directly on top of the stove.</p>
<p>But really, for a lazy engineer like me, all of this was too much physical labour. I took it back to the workshop.</p>
<h1 id="doors">Doors</h1>
<p>First thing first, I fixed the doors. That is, I put a 5 mm stainless steel rod and a few bushings in.</p>
<p><img src="/assets/images/2012.07.14-damaged_spring_on_drum.jpg" alt="Drum door with stainless steel rod, damaged spring visible" /></p>
<p>The spring that opens the door had to be cut, since <em>ioch</em> damaged half of it while trying to scrape the plastic out. I just burnt it out later, but the spring was already twisted.</p>
<h1 id="motor-mounting">Motor mounting</h1>
<p>We also got a new motor: 4,0 W (although looks like 40), 975 RPM, with a reduction gearbox that brings it down to 10 RPM. Solid-core Soviet unobtanium, made in 1979. I cut and tapped a mounting bracket that attaches to the legs with two screws.</p>
<p><img src="/assets/images/2012.07.14-motor_mount.jpg" alt="Motor and mounting bracket" /></p>
<p>Mounted, it looks like so.</p>
<p><img src="/assets/images/2012.07.14-motor_attached.jpg" alt="Motor, mounted on the side" /></p>
<h1 id="motor-coupling">Motor coupling</h1>
<p>What I forgot to photograph in the previous post and therefore couldn’t properly explain was how the drum was being rotated. So here’s the catch.</p>
<p>The shaft of the motor had a small steel gear attached to it.</p>
<p><img src="/assets/images/2012.07.14-motor_shaft_gear.jpg" alt="Gear on motor shaft" /></p>
<p>I took it off and welded two thick strips of steel to it.</p>
<p><img src="/assets/images/2012.07.14-spinner_grip_head_welded.jpg" alt="Modified gear to go back on the motor's shaft" /></p>
<p>Why would I do that? Here’s why.</p>
<p><img src="/assets/images/2012.07.14-spinner_grip_head_in_action.jpg" alt="Shaft-drum coupling method" /></p>
<p>This is how the motor is coupled to the drum. A T-shape is screwed to the axis shaft of the drum, and the motor shaft’s head (modified gear in this case) has a “prong”. As the motor rotates, the prong pushes on the T-shape, forcing the drum to rotate.</p>
<p>This method has a lot of slack, an advantage in this case, since things aren’t perfectly centered. It’s probably been patented by some wanker, too.</p>
<h1 id="the-test">The test</h1>
<p>There were no coffee beans around this time, so I used a box of screws. It felt something like 1,5 kg. And it worked! The motor spins.</p>
<center><iframe width="420" height="315" src="https://www.youtube.com/embed/Q8UA0ub4j-Q" frameborder="0" allowfullscreen="yes">Washing machine drum coffee roaster (test run), on Youtube.</iframe></center>
<p>It is still to be <a href="/2012/07/27/coffee_roaster_complete/">tested with real beans</a>, though.</p>
Drum coffee roasterrxdtxd2012-07-04T00:00:00+03:00https://wemakethings.net/2012/07/04/coffee_roaster<p>There are two reasons why this contraption came to be.</p>
<p>First, we like coffee. We like a lot of coffee, a lot. Ground coffee from the shop is crap, most of it. Unground beans are twice as expensive. What do you usually do in this case?</p>
<p>You <a href="http://www.cafe-libertad.de/shop/">buy it online</a>.</p>
<p>Second, you eventually buy several bags of unground beans, and then realise you have no idea how to roast them.</p>
<p>There are a lot of simple and time-consuming methods. Roasting <a href="https://www.youtube.com/watch?v=LMEpSuGboZc">in a frying pan</a> takes, say, 3 hours of non-stop work to make a kilo of the good stuff. You can’t stick a lot <a href="https://www.youtube.com/watch?v=gslCRG1aBBE">in the oven</a>, too. One could even do it <a href="https://www.youtube.com/watch?v=D0Y5ojdVWxE">in a popcorn popper</a> or <a href="https://www.youtube.com/watch?v=Vd4_CWEnaYg">between two meshes</a>.</p>
<p>This last video got me thinking. A cross between that and an <a href="https://www.youtube.com/watch?v=DYsWECLaakI">industrial drum</a> would be nice. Perhaps a top-loaded washing machine drum, with an electric motor on the side and a gas stove beneath.</p>
<h1 id="drums-and-bearings">Drums and bearings</h1>
<p>Consequently, I was much pleased when this appeared in the workshop.</p>
<p><img src="/assets/images/2012.07.04-washmachine_drum.jpg" alt="Washing machine drum, covered in lime and soap" /></p>
<p>Oh, the things that break and get thrown out!.. My heart sings as I wash them in acid.</p>
<p>This stainless steel drum has a bearing on either side of the axis. You can see one in the picture above. We got two precision circular mounts for the bearings, made by a professional machinist.</p>
<p><img src="/assets/images/2012.07.04-bearing_mounts.jpg" alt="Bearing mounts" /></p>
<p>There was also a drawing somewhere on that table, but the whole project went artsy so early on the drawing is not relevant to anything.</p>
<p>I welded the mounts to strips of 4 mm metal, working it in small increments to prevent warping.</p>
<p><img src="/assets/images/2012.07.04-bearing_mounts_welded.jpg" alt="Bearing mounts, welded" /></p>
<h1 id="legs">Legs</h1>
<p>The roaster stands on four legs, two on either side, welded to the metal strips on the outside (so they don’t touch the rotating drum). Square pipe was used here.</p>
<p>Thickness is more or less arbitrary. As to length, I used the diameter of my drum as the dimension. Make it such that the legs and ground form an equilateral triangle. As you remember from <a href="https://en.wikipedia.org/wiki/Equilateral_triangle">school</a>, it is then trivial to calculate their position on the side strips.</p>
<p><img src="/assets/images/2012.07.04-legs_welded.jpg" alt="Legs welded to side plates, aligning motor mount brackets" /></p>
<h1 id="motors">Motors</h1>
<p>The above image also shows how a motor is to be attached. There are two brackets pointing outwards. A plate of some sort is attached to the motor, and that in turn attaches to the brackets. Why a proxy? Because there’s only so much space. And it’s good to be motor-agnostic in case a motor doesn’t work.</p>
<p>Anyway, the attachment plate has threaded taps to screw the motor on. There are also two threaded taps on the sides of the plate. Their centers are set apart as far as centers of the holes on the brackets. The latter are much bigger (10 mm against 6 mm), so that after the motor is mounted, it can be pushed around a little. This allows centering the motor along the drum’s center axis.</p>
<p>You can see now that our thinking here was quite center-centered. That’s for a reason: a motor will be spinning quite a load here. Speed is negligible enough as far as bearing alignment is concerned, but the motor’s grip alignment isn’t. Besides, it gives an angle at compensating misproper alignment in everything else.</p>
<p>This scheme is implemented on both sides of the drum. They are not identical: there are four brackets on the other side, which allows mounting a much heavier three-phase motor to be controlled with <em>miceuz’</em> <a href="http://blog.hardcore.lt/mic/archives/011040.html">variable frequency drive and a foot pedal</a>.</p>
<p><img src="/assets/images/2012.07.04-motors_from_sides.jpg" alt="A motor on either side of the drum" /></p>
<p>Of course, only one motor is to be mounted at any given time.</p>
<p>I forgot to take pictures of how the motor actually grips the drum to spin it. Maybe in a <a href="/2012/07/14/coffee_roaster_revisited/">follow-up post</a>.</p>
<h1 id="ribs-and-assembly">Ribs and assembly</h1>
<p>When the leg parts that go on the sides of the drum were all welded together and cooled down, I inserted the bearings and gently tapped them in using a round piece of wood and a hammer. I then assembled them on the drum and measured the distance between the legs on either side.</p>
<p>There were two holes on each leg, drilled prior to all the welding (for ease of manufacture). They are further away from the top end than the radius of the drum.</p>
<p>I measured the distance between the legs on opposite sides of the drum, and cut four pieces of the same square pipe I had. These are for stability, to disallow mischievous acts of falling apart and rolling away.</p>
<p><img src="/assets/images/2012.07.04-side_rib.jpg" alt="Ribs" /></p>
<p>Accidentally, it allows taking the machine apart, and putting most of it <em>inside</em> the drum, for easy storage and transportation.</p>
<h1 id="turning-beans">Turning beans</h1>
<p>You might have also noticed the drum has largish holes along its outer surface. One could weld them over to prevent beans from falling out. But I screwed in some screws instead. They are, of course, stainless steel.</p>
<p><img src="/assets/images/2012.07.04-inside_screws.jpg" alt="Screws from the inside of the drum" /></p>
<p>This helps in turning the beans while the drum rotates.</p>
<h1 id="tests">Tests</h1>
<p>One thunderous rainy night, as soon as all the chores were done, we decided to have our share of fun and run a few tests.</p>
<p>And I hate to disappoint, but both motors failed and there are no videos of proof.</p>
<p>The smaller motor, 2 RPM, four puny watts of power in a reduction gearbox, failed to lift 1,5 kg of beans. Not enough torque, <a href="https://en.wikipedia.org/wiki/Torque">lever-arm distance</a> too big.</p>
<p>The bigger one, too, couldn’t lift the weight all by itself: it doesn’t have a reduction gearbox, although it does have power (140 W). However, if the drum is first spun by hand, and the motor is then turned on, it picks up momentum and keeps spinning jolly. Except one thing: it spins too fast, like a centrifuge, and all the beans get stuck to the drum’s surface. If there was a burning stove beneath, the beans would get roasted mighty uneven.</p>
<h1 id="manual-override">Manual override</h1>
<p>So I took both motors off, and welded a screw to one side instead, head inwards, and screwed a handle from a meat grinder to it.</p>
<p><img src="/assets/images/2012.07.04-roaster_manual.jpg" alt="Roaster with handle for manual operation" /></p>
<p>We are yet to <a href="/2012/07/14/coffee_roaster_revisited/">test this setup</a>.</p>
Push frame for Mercedes-Benz 207Drxdtxd2012-06-26T00:00:00+03:00https://wemakethings.net/2012/06/26/push_frame_for_mb_207d<p>(EDIT: I have found out that this kind of equipment is usually called “body rollers”, or an “auto rotisserie”, – and quite often provides another crucial degree of rotational freedom, like <a href="http://www.rollerhoop.com/">this one</a>. That’s my first search hit, just an example, I’m unaffiliated.)</p>
<p>Making one piece of <a href="/2012/05/17/engine_hoist_boom_extension_for_mb_207d/">custom supplementary hardware</a> is never enough. I was talked into building this one, too, and it’s proven to be extremely useful.</p>
<p>Note that this is not a step-by-step how-to on building a push frame for your own MB 207D (or 307D, or any other). It’s more a description of the thinking and manufacturing process, with a few pitfalls mentioned. Same principles can be used for other vehicles. There are certainly other ways of achieving the same, better or worse.</p>
<p>And I can’t be held responsible if a ton of steel crushes someone because of something read online. Duh!</p>
<h1 id="grand-plan">Grand plan</h1>
<p>The issue is as follows: I need to move the van body. Sideways. Then turn it around 180° in a 6x6 meter area. Over and over again.</p>
<p>We first thought putting frames under each wheel, but decided against it for two reasons. First, I wouldn’t be able to remove neither the van’s wheels, nor the axles. Second, the small frame wheels, 16 of them, would cost too much. No, really. Their price is not proportional to size.</p>
<p>We reckoned there’s another approach: a frame for the entire body. It goes like this.</p>
<p>At the front, the radiator is mounted on a cross bar, which is attached to the chassis by eight M10 bolts. I have already removed the entire engine, so anything can be mounted using these screw holes. But here’s a picture from a long time ago, so you can understand what I’m writing about.</p>
<p><img src="/assets/images/2012-06-26-engine_bay.jpg" alt="Mercedes-Benz 207D engine bay, front paneling removed" /></p>
<p>At the back, the tow bar can be removed, giving another eight holes, also M10.</p>
<p><img src="/assets/images/2012-06-26-towbar_removed.jpg" alt="Mercedes-Benz 207D towbar removed" /></p>
<p>Therefore, there are four stable mount points, where plates can be attached to the chassis. Weld four vertical “legs” to these plates – two at the front, two at the back. Weld these legs to cross bars with wheels at both ends. You’ve got yourself a minimal frame.</p>
<p>I started off by mocking up a drawing, then taking measurements. I kept revising as I progressed, and here’s the final version (rear at the top, front at the bottom, dimensions not to scale):</p>
<p><img src="/assets/images/2012-06-26-drawing.jpg" alt="Push frame drawing" /></p>
<p>Notice there’s a few dimensions missing – most importantly, everything around the mount points. I’ve written them down on the plates themselves and forgot to put them in the drawing. Anyway, the spacing between bolts’ center-points are: 97x82 mm at the front, 69x46 mm at the back. Don’t trust me on this one, though, I’m from the Internet.</p>
<p>The spacing for wheel mount plates depends solely on the wheels you’ve got.</p>
<h1 id="attaching-the-frame-to-the-chassis">Attaching the frame to the chassis</h1>
<p>I first manufactured these 4 plates. They’re made out of a steel strip 8 mm thick, 100 mm wide, 180/140 mm long for the front/back respectively. Nothing too precise here. What <em>has</em> to be precise is where you drill the holes. I went and checked immediately after.</p>
<p><img src="/assets/images/2012-06-26-front_plate_test.jpg" alt="Front plate bolt hole alignment test" /></p>
<p>The bolts are 30 mm long, but that’s not critical. They can be unnecessarily long and give one a pain in the ass when tightening the nuts, if such is the desired effect.</p>
<p><img src="/assets/images/2012-06-26-rear_plate_test.jpg" alt="Rear plate bolt hole alignment test" /></p>
<p>Here the bolts should be at least 80 mm long (not counting the head, of course). Note that there’s only about 5 cm of space on the other side, so the bolts can’t be inserted the other way around.</p>
<h1 id="wheel-assembly">Wheel assembly</h1>
<p>I then built two lower cross bars that the wheels attach to.</p>
<p>As mentioned, this depends mainly on the wheels on hand. I had four big ones, the specs say they can hold up to 500 kg each. The van’s body weighs about 500-700 kg, plus 100-200 kg for each axle – a total of 700-1100 kg, unevenly distributed.</p>
<p>We decided it would hold.</p>
<p>For the cross bar, I used 60x60x4 mm square pipe, because it felt solid enough. The van is about 1820 mm wide, so I cut my two pipe segments to that length, then cut two pieces of 40x6 mm strip for each wheel (a total of 8 strips).</p>
<p>40x4 mm would have worked just as well – the cross bar is 4 mm thick, after all, and if something broke under the weight, it would be the cross bar. But <em>pwf</em>, who went to the metal depot, wanted to prove they’ve got stuff that’s not available if you’re ordering online. So 40x6 mm it is.</p>
<p>Anyway, here’s a bottom view of the wheel mount. It’s pre-drilled and TIG-welded for alignment.</p>
<p><img src="/assets/images/2012-06-26-wheel_mount_point.jpg" alt="Wheel mount cross bar, bottom view, TIG-tac-welded for proper alignment" /></p>
<p>In cases like this, I would now rather weld it on with the wheels attached – less toying around with precise positioning.</p>
<p>Here’s the wheel assembly.</p>
<p><img src="/assets/images/2012-06-26-wheel_assembly.jpg" alt="Wheel assembly" /></p>
<p>From 10 o’clock, clockwise: mount plates, rear and front; assembled wheel mounts, top and bottom views; disassembled wheel mount, exploded view.</p>
<p>Notice that the holes I drilled are not center-aligned. This, again, is solely due to the wheels I’m using.</p>
<p>To make these strips identical, I first drilled 4 mm center-holes in one piece, then used it as a template for the rest. This is standard practice. If the template is screwed, then everything is screwed, then I am screwed. So I was vewy-vewy-caweful.</p>
<p>After TIG-welding the strips to the cross bar, I stick-welded them, since this is faster and cheaper.</p>
<h1 id="legs">Legs</h1>
<p>At this point, I had two fully assembled cross bars with wheels. Really dangerous to ride around the workshop.</p>
<p><img src="/assets/images/2012-06-26-cross_bar.jpg" alt="Cross bar with wheels and rear mount plates" /></p>
<p>I could measure their height, and how much the chassis mount plates protruded, so I could now decide how long my legs should be.</p>
<p>I jacked the van up and did that, then cut appropriate lengths off a 50x50x2 mm square pipe. This can be a lot thinner than the cross bar, since the main force applied is <a href="https://en.wikipedia.org/wiki/Compressive_strength">compression</a>, not <a href="https://en.wikipedia.org/wiki/Bending">bending</a>. Also, we had that as a leftover. And it doesn’t weigh too much, which at this point was starting to become an issue.</p>
<p>I also put in square pipes diagonally, to prevent the legs breaking off sideways.</p>
<p>Long story short, here’s how it looked at the back before I screwed it to the chassis.</p>
<p><img src="/assets/images/2012-06-26-rear_unmounted.jpg" alt="Rear frame part, unmounted" /></p>
<p>I don’t particularly like how the legs are welded to the mount plates. I’d now rather have spent a lot of time cutting away slots, so one inserts into the other. Too late, Captain Hindsight.</p>
<h1 id="final-touches">Final touches</h1>
<p>At the front, I had to put in some spacers for better vertical alignment.</p>
<p><img src="/assets/images/2012-06-26-front_mounted.jpg" alt="Front frame part, mounted" /></p>
<p><img src="/assets/images/2012-06-26-front_mounted_closeup_plate.jpg" alt="Front frame part, mounted, close-up with spacers visible" /></p>
<p>At the back, it fit as planned.</p>
<p><img src="/assets/images/2012-06-26-rear_mounted.jpg" alt="Rear frame part, mounted" /></p>
<p>The whole thing didn’t feel stable enough when I tried to push the van, so I screwed a segment of metal stairs to both parts of the frame lengthhwise, underneath the van. Call it a spine. You can see a part of it in the picture below.</p>
<p><img src="/assets/images/2012-06-26-spine.jpg" alt="Front axis, its wheels removed, spine visible" /></p>
<p>The spine is removable and can be attached whether or not the axles are still in place. When I was sure the whole thing wouldn’t collapse, I removed the axles.</p>
<p><img src="/assets/images/2012-06-26-van_without_axles.jpg" alt="The van, side view, axles removed" /></p>
<p>One day, I will gimp the frame out, and the van will levitate.</p>
Plant watering alarm FIALmiceuz2012-06-21T00:00:00+03:00https://wemakethings.net/2012/06/21/plant_watering_alarm<p><strong>Update</strong> A new working vesion of <a href="http://wemakethings.net/chirp">plant watering alarm</a> is available for sale! It’s open source and it goes <a href="http://wemakethings.net/chirp">Chirp!</a></p>
<p>If you want to know where I went after writing all of this, check out these posts:</p>
<ul>
<li>
<p><a href="http://wemakethings.net/2012/09/26/capacitance_measurement/">Capacitance measurement using low pass filter</a></p>
</li>
<li>
<p><a href="http://wemakethings.net/2013/06/07/chirp-plant-watering-alarm/">Chirp! - the plant watering alarm</a></p>
</li>
</ul>
<p>Well, living together with a person comes with some responsibilities that are to be tackled. Like watering plants. My friend I’m sharing an apartment with was leaving for a couple of weeks and has burdened me with a task to take care of several pots with alien life forms. After i was finished with my pot-growing experiments long time ago, i didn’t care enough about plants and i didn’t expect myself to be out of nerd zone enough to be aware of this task as it’s not cyclic and depends on different external factors such as ambient humidity and temperature. So, i came up with a hi-tech solution: Plant watering alarm that would notice me in non-too-much-intrusive way that it’s time to take care of other species. After some simulation i was quick with a fully working prototype in the first go!</p>
<p><img src="/assets/images/2012-06-21-plant_alarm_prototype.jpg" alt="First prototype" /></p>
<p>As currently I’m very much in analog electronics and i had heaps of free op amp samples lying around, i went with a fully analog solution as i like things to be as basic as possible.</p>
<p><img src="/assets/images/2012-06-21_plant_alarm_schematics.png" alt="Circuit" /></p>
<p>The circuit works as follows:</p>
<p>Electrodes in earth act as a variable resistor, resistance of which depends on amount of water in soil, it forms a voltage divider with R5. While this voltage is above a voltage on non inverting input of op amp, created by R3, R2 and R1, nothing happens. When soil dries out, it’s resistance increases and voltage on inverting input falls below the threshold. Output of op amp swings to positive rail, lighting up a LED and making click in piezo beeper. Voltage on inverting input changes to another value, and C1 is charging up through R4 until it reaches that value. Then output of op amp goes low clicking a piezo buzzer once more, C1 discharges thruough R5 and the cycle repeats. In general it’s a relaxation oscillator with hysteresis set by R2 and R1.</p>
<p>Two days later after i woke up, I’ve heard a silent clicking, it’s time to water plants! Win!</p>
<p>As i have no job and still have no intentions to get one, i instantly saw dollar bills in it. I could make a product out of this and sell it to fellow geeks and whomever else, all i need is to make it battery operated and low on power consumption! I got these extremely low power op amps from TI - OPA379, with input high, the device was consuming 6 micro amps, it could work years on 3V lithium button cell battery!</p>
<p>Well, the devil was hiding not far away. The resistance of the soil in kilo-ohm range, i measured about 500K in extremely dry pot and 10K in freshly watered plant, this means, the main resistive divider would draw 60uA alone, it would drain the battery in 4 months and it’s unacceptable. I’ve had an idea about inverting input by putting a mega ohm resistor from VCC and connecting the plant to ground, buffering and amplifying the voltage by another op amp, but the electrodes in soil act as a battery too, producing ~40mV of voltage, which varies wildly on the type of soil, fertilizers and bunch of random stuff, so i had to scrap the idea. Maybe I’ll try it by measuring capacitance between electrodes. Well, back to microcontrollers…</p>
Engine hoist boom extension for Mercedes-Benz 207Drxdtxdpwf2012-05-17T00:00:00+03:00https://wemakethings.net/2012/05/17/engine_hoist_boom_extension_for_mb_207d<p>I’d like to work on the body of this van without fretting too much about getting sand in her… well, important places. Which means stripping everything, including the engine.</p>
<p>Taking it out on this model is pretty straightforward. Literally: unless the van is lifted and the front axle removed, the engine and transmission can only be removed in a straight horizontal trajectory.</p>
<p>The engine hoist we’ve got is made for light vehicles, where the engine is lifted out vertically. The hoist boom, when horizontal, is 20-30 cm too high in my case, and cannot be adjusted.</p>
<p>One could, of course, modify the hoist itself to be adjustable, but there’s a simpler solution: a purpose-built angled boom extension for a given van.</p>
<p>I started off by measuring the cross section of the original extension, which happened to be 60x60x4 mm. Got a meter of that.</p>
<p>Then took the hoist to the van, removed the original extension, lifted the boom slightly over the engine’s top line, and marked an angle. Inside the boom, this extension wanna-be o’ mine went slightly over the hydraulic jack.</p>
<p>Took the square pipe to the bench and cut at the marked line, then squared off the remainder by cutting out a triangle.</p>
<p><img src="/assets/images/2012-05-17-cutout-1.jpg" alt="Extension cutout" /></p>
<p>This piece came very handy for reinforcement.</p>
<p><img src="/assets/images/2012-05-17-cutout-2.jpg" alt="Extension puzzle pieces, before welding" /></p>
<p>The smaller square pipe is 30x30x4 mm, and there are two of them stacked in this side view. We reckoned smaller pipe would give more operating space in the engine bay. Two sections of approx. 60 cm were needed, and exactly two sections of approx. 60 cm were available (after I cut them off from longer pieces).</p>
<p>The engine here is an OM616, which has three suspension points. I took three big nuts and dropped them in an acid bath. Took ‘em out, dropped them in a lye bath. Took ‘em out, rinsed with water. These are improvised lugs.</p>
<p>After gathering the puzzle pieces, I handed them off to a professional welder friend (who happened to be procrastinating with a bottle of JD). Here’s what came back (this is not a shotgun):</p>
<p><img src="/assets/images/2012-05-17-ext-1.jpg" alt="Boom extension, side-view" /></p>
<p><img src="/assets/images/2012-05-17-ext-2.jpg" alt="Boom Extension, underside" /></p>
<p>Here’s how it looks attached to the boom:</p>
<p><img src="/assets/images/2012-05-17-hoist-modded-closeup.jpg" alt="Attached boom extension" /></p>
<p>A comparison of boom extensions, original and custom:</p>
<p><img src="/assets/images/2012-05-17-hoist-compare.jpg" alt="Boom extensions, original and custom" /></p>
<p>Notice how the new one looks a lot more sinister than the original. And no, that is not piss in the corner.</p>
<p>Finally, here it is engaged, doing what it does well:</p>
<p><img src="/assets/images/2012-05-17-motor-on-hoist.jpg" alt="Ich habe einen großen Fisch, ja!" /></p>
<p>Used carabiners for suspension here – chains would have been too constricting.</p>
Ball joint separator, part tworxdtxd2012-05-04T00:00:00+03:00https://wemakethings.net/2012/05/04/ball_joint_separator_part_two<p>The very next day after <a href="/2012/05/02/ball_joint_separator/">this</a>, I went and got myself a “proper” ball joint separator. It was the right thing – did the job in a matter of minutes. Didn’t even have the time to make tea.</p>
<p>The other end of the rod had a torn boot, so I took that off, too. Again, without tea.</p>
<p>Here’s how it looks.</p>
<p><img src="/assets/images/2012.05.04-ball-joint-separator.jpg" alt="Ball joint separator and tie rod with torn boot" /></p>
<p>The separator is made of pretty good steel, and the pushing screw has a ball joint of its own, to reduce friction while turning. If you intend to make one, take these factors into consideration.</p>
Ball joint separatorrxdtxd2012-05-02T00:00:00+03:00https://wemakethings.net/2012/05/02/ball_joint_separator<p>I’ve got this old Mercedes-Benz 207D camper minivan. It’s a proper minivan, owned in its better days by a bourgeois deutchlander. Which means it’s fit out for short summer trips, with crammed living quarters and half the back taken by a toilet room. The toilet itself, of course, is missing. No heater, no insulation.</p>
<p>Or at least it was like that, before I decided to tear it all up and re-purpose it for year-round van dwelling.</p>
<p>Removing everything down to the panels revealed some rust. so I decided to get to the metal frame, which revealed considerable rust, especially around aluminum rivets. Before you know it, the van has no windows, no dashboard, half the engine bay is stashed in boxes, and I’m struggling to separate the <a href="http://en.wikipedia.org/wiki/Pitman_arm">pitman arm</a> from the tie rod. Not that there’s something wrong with the steering – I just need an empty metal shell to work with.</p>
<p>A few words on what I’m trying to do. Have you seen Sylvester Stallone in <a href="http://en.wikipedia.org/wiki/Over_the_Top_(film)">“Over the Top”</a>? Then you’ve seen nothing. One can not just wrestle with a pitman arm. It is tough and made of steel. It is <a href="https://www.youtube.com/watch?v=jc8glzE6eeo">wedged in beyond any specs by righteous muffins</a>. It is hammered in even more by every rock rolling on the road.</p>
<p>Therefore, one needs a ball joint separator.</p>
<p>And I could have gone and bought one, but decided to practice some <a href="http://en.wikipedia.org/wiki/Gas_tungsten_arc_welding">TIG welding</a> instead. I’ll need this skill anyway by the time I replace every rotten bit of the van.</p>
<p>The results, sadly, are negative. Maybe since it’s all made of scrap metal I found under the table. Here’s the first version:</p>
<p><img src="/assets/images/2012-05-02-a-puller-v1.jpg" alt="Ball joint separator, v1" /></p>
<p>The middle screw is the pusher rod. Two screws on the sides have flimsy grips. Turning the middle screw pushes on the ball joint finger, grips pull the pitman, and it comes off. Or such was my idea.</p>
<p>In reality, the grip screws bent sideways, their grabbing plates had bent, too, and nearly slipped off.</p>
<p>No biggie, replaced it with a single piece of 5 mm plate, cut out in a suitable shape, that attaches like so:</p>
<p><img src="/assets/images/2012-05-02-b-puller-v2.jpg" alt="Ball joint separator, v2" /></p>
<p>Looks a lot more solid, eh? It had bent, too. A little. I kept on pushing with a hand wrench, since the pneumatic would only hiss at this point, until the screw would turn no more, and the head snapped off:</p>
<p><img src="/assets/images/2012-05-02-c-puller-failure.jpg" alt="Ball joint separator, v2, failure" /></p>
<p>Oh well. Pitman is strong. I’ll either have to further refine this thing – shorter, stronger screws, a metal ball from a bearing to reduce friction, and so on – or just scrap it and <a href="/2012/05/04/ball_joint_separator_part_two/">buy a “real” one</a>.</p>
<p>Or maybe cover it all with a black bag and pretend it’s not there while I’m working on the body.</p>
Volkswagen Passat B2 water pump pulley holderrxdtxdvarious artists2012-04-30T00:00:00+03:00https://wemakethings.net/2012/04/30/volkswagen-passat-b2-water-pump-pulley-holder<p>We all know the importance of changing engine belts regularly. The knowledge by itself, though, does not prevent them from evaporating on the highway.</p>
<p>This happened to a certain <a href="http://en.wikipedia.org/wiki/Volkswagen_passat#B2_.28Typ_32B.2C_1981.E2.80.931988.29">folks’ wagon</a> we are acquainted with. Given the opportunity, we decided to change the whole lot: the power steering belt, the alternator belt, and the water pump belt.</p>
<p>The first one was easy, the second required some yoga, and the third seemed down right impossible to access without disassembling the front of the vehicle.</p>
<p>Or at least the water pump pulley. Which was held tight by three allen screws, which could not be unscrewed, because the pulley would rotate instead. It is, after all, a pulley – that’s what they do.</p>
<p>You know what our fathers would have done in this case. We surely didn’t, so we went online.</p>
<p>Long story short, we found <a href="http://www.germanautoparts.com/images/large/5ed123085327bfd06f632aedf579203f.jpg">special tools similar to this</a>. Paying 30$, waiting for a week and using it twice didn’t sound exactly right. So <em>various artists</em> (who did most of what I’m describing) cut a similar shape from a piece of 2.5 mm sheet metal.</p>
<p><img src="/assets/images/2012-04-30-pulley-holder.jpg" alt="Water pump pulley holder tool" /></p>
<p>I can’t give the exact measurements, they’re somewhere in <em>adude’s</em> notebook, but the 3 holes are approx. 14 mm in diameter, set out about 22 mm from the center point. The middle has to be cut out for a firm grip on the pulley.</p>
<p>If you intend to make one, have 6 holes instead of 3. The reason here is the tool can only be turned 60° freely inside the engine compartment. The blueprints, though, might look like a zionist conspiracy.</p>
dmx-dimmer ready for testingrxdtxd2012-04-09T00:00:00+03:00https://wemakethings.net/2012/04/09/dmx-dimmer-ready-for-testing<p>I’ll document the developments that happened since the <a href="/2012/01/24/dmx-dimmer-introduction/">previous post</a>, mainly for historical purposes.</p>
<h1 id="power-safety-during-prototyping">Power safety during prototyping</h1>
<p>The power connector (screw terminals) on the slave board weren’t sturdy enough and would jiggle if wiggled. Then the prototype board got burned – for a whole different reason, though.</p>
<p><img src="/assets/images/2012-04-09-burnt_power_connector.jpg" alt="Burned power terminals on slave board" /></p>
<p><strong>Lesson:</strong> power safety isn’t something to “implement later”.</p>
<p><strong>Tips:</strong>
* use terminals with paired pins for each connection, or connectors with metal casing that can be grounded;
* if using stranded wires, at least tin them to prevent shorts;
* have a fuse for each power user.</p>
<h1 id="whats-3d-rendering-good-for">What’s 3D rendering good for?</h1>
<p>If you’re wondering why would anyone want 3D rendering functionality in their EDA, just look an the lower side of the photo above. See that huge grey bulb? It’s a 1 mF electrolytic capacitor. I thought the SMD version was going to be small. And it was, compared to a through-hole. Still, a few millimeters too tall for this application.</p>
<p><img src="/assets/images/2012-04-09-bent_pads.jpg" alt="SMD capacitor turned though-hole" /></p>
<p>Soldered it out, drilled a few holes, bent the pads into pins, and soldered it in on the other side.</p>
<p>Then, there were a few spacing issues, mainly with mount screw holes. I was too lazy to go looking for a footprint as trivial as this, and used vias with fat copper rings instead. The tolerances were too small, though, so screwheads ended up getting over tracks, connectors, everything.</p>
<p><strong>Lesson:</strong> think about physical design, use 3D if available (KiCAD and EAGLE have it).</p>
<h1 id="stable-dimming">Stable dimming</h1>
<p>I’ve previously had some issues with lamp flicker. Weirdly enough, it would disappear after connecting an oscilloscope. I still haven’t figured this out, by the way. Thought it was noise in power, ground or zero crossing, but debugging led nowhere. Frustrated, I decided to do some meditative code cleanup.</p>
<p>Which turned out to be a great idea. It showed that timer resetting was still being done in a software interrupt routine. This creates delays, since processor state has to be pushed onto the stack first. Resetting the timer in hardware (which I assumed I had been doing all along) fixed the issue and gave a nice homogeneous glow.</p>
<p><img src="/assets/images/2012-04-09-filament_glow.jpg" alt="Filament glow" /></p>
<p><strong>Lesson:</strong> don’t assume you’ve got things right, and check; also, don’t assume you’ve already checked; avoid infinite recursion.</p>
<h1 id="real-men-wind-their-own-chokes">Real men wind their own chokes</h1>
<p>… mainly because they’re too expensive. The chokes, of course, not men.</p>
<p><img src="/assets/images/2012-04-09-handwound_choke.jpg" alt="Hand-wound heavy duty choke in a dimmer module" /></p>
<p>Here’s one used in a dimmer module. It’s a ferrite toroid core with 2 mm wire wrapped around it. 2 mm diameter gives a 3.14 mm<sup>2</sup> cross section, which is slightly overkill, and definitely too tough to wind. I’d aim for 1 mm<sup>2</sup> per 10 A. <a href="/2013/03/03/dmx-dimmer-winding-chokes/">Double-wound with thinner wire</a>, perhaps, to ease the chore.</p>
<h1 id="module-overview">Module overview</h1>
<p>Here lies dmx-dimmer, with one of each modules.</p>
<p><img src="/assets/images/2012-04-09-dimmer_modules.jpg" alt="Dimmer modules" /></p>
<p>I’ve made two revisions of the power dimmer board, with different triacs. <em>r0</em> was used during initial prototyping, to avoid running high currents through the breadboard. It doesn’t have a choke. <em>r1</em> had some layout quirks, which made running a proper test (with a 2 kW fixture) impossible.</p>
<p>It also looks like a rat’s nest due to all the wires. Some were simply soldered to the board. Bad idea! Move the boards around too much – and they break. Leave them by the table’s edge – and they fall. A remarkable annoyance.</p>
<p><strong>Lesson:</strong> don’t make a board unless you intend to test it any time soon.</p>
<p><strong>Tips:</strong>
* a <a href="http://en.wikipedia.org/wiki/TRIAC">triac</a> is <em>not</em> symmetric, if it doesn’t trigger, you might have to swap its MT1 and MT2 connections;
* soldered wire connections are not OK for prototyping.</p>
<h1 id="last-notes">Last notes</h1>
<p>I have yet to measure power usage. And many other things. This will have to collect dust for a while, though – safely, inside a box. I packed it all up and went to do something entirely different. The updated designs are available at <a href="https://github.com/rxdtxd/dmx-dimmer">GitHub</a>.</p>
<p>Strangely enough, I also stumbled upon <a href="http://www.engbedded.com/semitone/">Semitone Lighting Controllers</a>, an open hardware project that’s been running since 2003. Somehow Google missed this last year. I would have just built a Semitone Diamond instead of doing all this!..</p>
<p><strong>Lesson:</strong> don’t trust a search engine.</p>
Cat heating padmiceuz2012-04-01T00:00:00+03:00https://wemakethings.net/2012/04/01/cat-heater<p>Every human associated with a feline knows that these domestic animals find laptop computers highly valuable. Why do they find these machines so fascinating? Is it because of their intristic property to produce heat? Or is it because it appears to be a highly important asset as humans tend to spend a reasonable amount of time attached to these devices every day? We couldn’t simply ask our feline friend, as she was quite busy tending herself, we could only guess…</p>
<p><img src="/assets/images/2012.04.01-cat_heater0.jpg" alt="Problem - a cat on a loptop" /></p>
<p>Well, fortunately we had some 0.2mm nichrome wire so we were able to make a quick prototype. By dropping 25 volts and having 130 Ohm resistance it was able to put out about 5W of heat. Well, actually our crappy power supply made from trash found on a street was not able to put out more.</p>
<p><img src="/assets/images/2012.04.01-cat_heater2.jpg" alt="A prototype" /></p>
<p>We had some cardboard saved from some free samples of semiconductor devices sent to us by one nice company so we used that as a base for our device.</p>
<p><img src="/assets/images/2012.04.01-cat_heater3.jpg" alt="A pad" /></p>
<p>Alpha was not very impressed with our invention</p>
<p><img src="/assets/images/2012.04.01-cat_heater5.jpg" alt="Slow start 1" /></p>
<p>You know the saying, cats don’t really give a fuck…
<img src="/assets/images/2012.04.01-cat_heater1.jpg" alt="Cats dont give a fuck" /></p>
<p>But maybe it’s not that bad after all…
<img src="/assets/images/2012.04.01-cat_heater6.jpg" alt="Slow start 2" /></p>
<p>Two days later - a WIN!
<img src="/assets/images/2012.04.01-cat_heater7.jpg" alt="WIN!" /></p>
Copper platingiochrxdtxd2012-03-26T00:00:00+03:00https://wemakethings.net/2012/03/26/copper-plating<p>Here’s what <em>ioch</em> was toying with last week.</p>
<p><img src="/assets/images/2012-03-26-plating.jpg" alt="Copper-plating a hard drive disc" /></p>
<p>It’s a copper-plated hard drive disc, still in the bath. It didn’t go particularly well, the thin copper film peeled off.</p>
<p>I have no interest in blogging other people’s stuff, so I’ll leave you with that: pretty pictures.</p>
Control a motor from a lighting consolerxdtxd2012-03-04T00:00:00+02:00https://wemakethings.net/2012/03/04/control-a-motor-from-a-lighting-console<p>A few months ago I was asked what it would take to drive a 3-phase AC induction motor from a lighting console. A specific variable frequency drive by Delta Electronics (<a href="http://www.delta.com.tw/product/em/drive/ac_motor/ac_motor_product.asp?pid=1&cid=1&itid=3">VFD-L series</a>) was provided. Coincidentally, <em>miceuz</em> was working on a <a href="http://blog.hardcore.lt/mic/archives/011040.html">variable frequency drive</a> of his own, so a motor that fit the purpose just happened to be lying around.</p>
<p>So everything that had to be done was a translation from <a href="http://en.wikipedia.org/wiki/DMX512">DMX512</a> (the console) to <a href="http://en.wikipedia.org/wiki/Modbus">Modbus</a> (the VFD).</p>
<p>I took my trusty <a href="https://metalab.at/wiki/Metaboard">Metaboard</a> and meditated. Quite conveniently, both DMX512 and Modbus are RS485 protocols, so a 75176 interface chip for each is all the hardware that is needed. Here’s the schematic I drew then and fished out from under the desk now. The table on the left is for bookbinding signatures and absolutely unrelated.</p>
<p><img src="/assets/images/2012.03.04-schematic.jpg" alt="75176 and ATMega interconnection" /></p>
<p>Writing the code was pretty simple, since I took most of it from the <a href="http://wemakethings.net/2012/01/24/dmx-dimmer-introduction/">DMX dimmer</a> project of mine. Which is going slow and steady, thank you.</p>
<p>The rest, dealing with Modbus, required a skim through the VFD’s manual, and is pretty much hard-coded. I let myself do this, since the goal was to see if it can be done at all, and the finished thing needed only to have speed control, nothing else. A lot more is possible, though, with the mentioned VFD. If I had to do that, I’d probably go with <a href="http://www.freemodbus.org/">FreeMODBUS</a>, a library for a number of embedded architectures.</p>
<p>To simulate a lighting console, I used <a href="http://qlc.sourceforge.net/">QLC</a> (software) and ENTTEC’s <a href="http://www.enttec.com/index.php?main_menu=Products&prod=70304&show=description">DMX USB Pro</a> (hardware). Keep in mind that if you want to use this setup on GNU/Linux, the former uses a not-invented-here approach to communicate with the latter, and you might need to blacklist the <code class="highlighter-rouge">ftdi_sio</code> kernel module.</p>
<p>Keeping the story short, after 6 hours of copying code around, I came up with <a href="https://github.com/rxdtxd/dmx-motor">this slackjob proof-of-concept</a> to control an AC induction motor using DMX, taking a few givens for granted. Mind you, a VFD for industrial automation is quite more common (and, therefore, cheaper) than professional theatre special effects equipment that does the same thing.</p>
<p>The last move I made was film it all, once, on the first camera that happened about. Here it is, in all its pixelated, shaky, moory glory.</p>
<center><iframe width="420" height="315" src="https://www.youtube.com/embed/lNdiwxo47Fc" frameborder="0" allowfullscreen="yes">3-phase AC Induction otor Controlled Using DMX, on Youtube.</iframe></center>
<p>And yes, I do call that a workshop.</p>
Repairing a Martin Atomic 3000 DMX stroberxdtxd2012-02-14T00:00:00+02:00https://wemakethings.net/2012/02/14/repairing-a-martin-atomic-3000-dmx-strobe<h1 id="fuse-blows-repeatedly">Fuse blows repeatedly</h1>
<p>I got my dirty hands on this nice fixture, a <a href="http://www.martin.com/product/product.asp?product=atomic">Martin Atomic 3000 DMX stroboscope</a>. What exactly happened to it is shrouded by mystery, since it happened too long ago for anyone to remember. Some facts, though, were relayed as follows:</p>
<ul>
<li>something blew on the board, and high currents destroyed the original fuse;</li>
<li>there was no time to wait for a “replacement” or “inspection by a qualified technician” (as is quite often the case with important equipment);</li>
<li>someone obtained the relevant components, soldered them in and changed the fuse;</li>
<li>the strobe, however, kept misbehaving, blowing the fuse repeatedly;</li>
<li>as such, it was eventually shelved.</li>
</ul>
<p>Here’s the part of PCB that took the damage:</p>
<p><img src="/assets/images/2012.02.14-atomic3000-spark-gap.jpg" alt="Atomic3000 PCB, with replaced components" /></p>
<h1 id="its-a-spark-gap">It’s a spark gap!</h1>
<p>Notice a few things, Dr. Watson:</p>
<ul>
<li>how a few caps are molded on the top, a sign that someone was in a hurry or just didn’t bother to flatten the playing field;</li>
<li>how it is all centered around two resistors, R127 and R136.</li>
</ul>
<p>A short browse gave a few threads with similar issues: one <a href="http://www.blue-room.org.uk/index.php?showtopic=11616">looking for a schematic</a> and another <a href="http://www.blue-room.org.uk/index.php?showtopic=25382">asking for advice</a>.</p>
<p>A schematic, indeed, is only available from Martin if you’ve passed some sort of ritualistic initiation. So I went on the internets’ underside and found it, and here’s the relevant part:</p>
<p><img src="/assets/images/2012.02.14-atomic3000-powerline-schematic.png" alt="Part of Atomic3000 schematic, showing the part that got blown away" /></p>
<p>And oh Abyss, those two resistors, put butt-to-butt, form a spark gap between LINE and NEUTRAL!</p>
<p>The thing about light fixtures is that they’re often used indoors. Indoors is often poorly ventilated. There is a lot of dust, which gets everywhere, especially into spark gaps. I’ve seen dust inside stepper motors, too, between the bearings of fans, covering heatsinks and integrated circuits to the point they can’t be seen!.. The horror, the horror…</p>
<p>Anyway, there’s not a lot that can be done except for regular cleaning (yeah, right). I’m sure Martin has also fixed this in their later revisions of the PCB. After all, the one in question is way back from 2001.</p>
<p>I couldn’t have not indulged myself, though, in the following way:</p>
<p><img src="/assets/images/2012.02.14-atomic3000-bigger-spark-gap.jpg" alt="Atomic3000 PCB, a-la fixed" /></p>
<p>Correct, it’s a bigger spark gap. I also changed the caps. And wiped off the rosin residue. The solderwork looks sloppier than it was before.</p>
<h1 id="ehm-fuse">Ehm… Fuse?</h1>
<p>Back to the issue at hand: why does it keep blowing the fuse? Well, it’s because not every fuse will do. You need a slow-blow fuse, says so in the manual. Martin can supply those for you, catalog number 05020040.</p>
<p>This is because the strobe draws up to 33 amperes at peaks, which happens when you run it in full-power mode with the blinder effect.</p>
<p>We’ve measured it with this:</p>
<p><img src="/assets/images/2012.02.14-current-meter.jpg" alt="Current meter setup" /></p>
<p>It’s a current transformer and a meter. The good thing about this is it shows effective current through the wires, not some derivative. When the strobe runs in normal mode, it draws current in bursts, and modern meters that measure magnetic flux would show all kinds of weird, like jumping fast from -50mA to 50mA, with the amplitude ramping up, eventually to 150A. Which can’t be true.</p>
<p>Anyway, with this setup, we’ve measured that the device draws very little on average in normal mode, around 18A in half-power blinder mode and well over 30A in full-power blinder. Mind, though, that this doesn’t last for long, since thermal protection kicks in and decreases lamp glow intensity – by limiting current.</p>
<p>The ultra-high power mode, though, lasts for a few seconds, which is enough to blow a glass fuse, even if it’s slow-blow. But a ceramic one can tolerate this. According to the datasheet of the one we bought, at 200% of the ampere rating, minimum “opening time” is 5 seconds. Which is probably enough.</p>
<p>So much for this “failure mode”.</p>
LPC1343 devboard, continuedmiceuzrxdtxd2012-02-02T00:00:00+02:00https://wemakethings.net/2012/02/02/lpc1343-devboard-continued<p>A few weeks passed, and the PCBs came. We went for minimum price, which means no electric testing and no masks. Therefore, no outlines for what to place where, or how to orient things; and a few misaligned vias – but they’re metalized properly, so what the heck.</p>
<p><a href="https://www.adafruit.com/products/281">Adafruit</a> still quotes 15-20 days till stock.</p>
<p>By now, <em>miceuz</em> has noticed a few more things we could’ve changed. Like replacing the 3.15V supervisor (U3) and EEPROM (U4) with more common chips. Oh well.</p>
<p><img src="/assets/images/2012.02.02-lpc1343-badvia.jpg" alt="LPC1343 devboard PCB" /></p>
Powering LEDs from mainsiochrxdtxd2012-01-29T00:00:00+02:00https://wemakethings.net/2012/01/29/powering-leds-from-mains<p>…with as few components as possible. Sorry for the blur, it was dark.</p>
<p><img src="/assets/images/2012.01.29-switches-with-backlights.jpg" alt="Power switch box with LED backlight" /></p>
<p>Here’s a box <em>ioch</em> made. It has eight quality thumb switches for their reliable “clunk!” and four backlight LEDs, mainly for the flare. To power LEDs from the mains, though, you’d need a transformer. That’s bulky, expensive and unimaginative.</p>
<p>So what’s the smallest schematic one could have, if 50 Hz flicker was not a problem? <em>John</em> remembered seeing something like this on the internet (and I zoomed out as much as I possible to make it even smaller):</p>
<p><img src="/assets/images/2012.01.29-minimal-led-power-schematic.png" alt="Minimal circuit to power LEDs from mains" /></p>
<p>The components’ values were selected using an online circuit simulator. The resistor has to be rated for high power, and the capacitor for mains voltage.</p>
dmx-dimmer introductionrxdtxd2012-01-24T00:00:00+02:00https://wemakethings.net/2012/01/24/dmx-dimmer-introduction<h1 id="whats-this-about">What’s this about?</h1>
<p>I’ve started working on this project slightly more than a year ago, during winter. Why is a rather lengthy story. By June development was finished (almost), I shelved the thing, made a backup, picked up my backpack and headed outdoors, where fun was to be had.</p>
<p>What I’ve been doing all this time until now is another long story. Among other things, it involved working as an apprentice light engineer at a theatre. The dimmers there were 30 years old and took up a room ten times the size of our workshop. If I showed you the photos, you’d say it was fake, or at least crazy. The reason it’s still there after all these years is the upgrade cost.</p>
<p>Anyway, a few weeks ago I registered at GitHub and <a href="https://github.com/rxdtxd/dmx-dimmer">pushed the project there</a>. Be warned, there’s a lot of turbulence. For example, at the time of writing, the firmware is a few commits behind the hardware – pinouts had to be changed on the Master board to keep things simple and allow homebrew manufacture. But I’m getting ahead of myself.</p>
<p><img src="/assets/images/2012-01-24-etched.jpg" alt="dmx-dimmer Master board after etching" /></p>
<h1 id="wasnt-it-already-available">Wasn’t it already available?</h1>
<p>Of course, I looked around before engaging in a project as big as this. And there’s a lot of schematics and open-source stuff available. Some are based on, you guessed it, Arduino. The closest to what I needed, though, was <a href="http://www.hoelscher-hi.de/hendrik/english/dimmer.htm">Hendrik Hölscher’s DMX dimmer</a>.</p>
<p>But it uses a rather old AVR microcontroller, runs off single-phase, and can have no more than 8 channels. I need something with components that won’t disappear from the market too soon, something that uses three-phase mains power (but can use one or two if that’s desirable), and allows 12 channels, more if feasible.</p>
<p>Or so I thought up a year ago. Of course, now I see other, better ways of achieving the same. Yet, I’m too anxious to re-design, so this will have to go.</p>
<h1 id="what-will-be-inside">What will be inside?</h1>
<p>All of it is organised in four types of modules.</p>
<p>A couple of status LEDs and an address switch are on the panel, available to the end-user. These settings and DMX512 data are received by a Master microcontroller, ATMega168, using SPI for the former and USART for the latter. The data is then distributed to three Slaves using SPI and a wacky scheme of SELECT/READY lines. These ensure the data goes where it has to, when it has to, and doesn’t get lost during time-critical interrupts. A Slave, ATTiny2313, receives its set of channel data, determines its controlled phase’s zero-crossing, and fires signals to actual dimmers, up to four of them. A dimmer opens a thyristor, which allows current to flow to the light fixture; a heavy-duty choke is involved, how heavy depends on the money or time one’s willing to spend.</p>
<p>At least that’s how it works right now. Tests were carried out using protoboards, and everything seemed fine. How well this scheme performs in real life, under the strain of real loads, is yet to be seen.</p>
<h1 id="when-will-this-be-available">When will this be available?</h1>
<p>I don’t know.</p>
<p>Currently, I have two other consuming projects. One of these I expect to post some time soon, too.</p>
<p>As mentioned before, the current state of affairs is always available on <a href="https://github.com/rxdtxd/dmx-dimmer">GitHub</a>. So if anything goes wrong, at least it’s not lost forever.</p>
<p>Today, I’ve etched the Master board and started populating it. Then it turned out I didn’t have a 16 MHz crystal on hand – luckily, one could be easily raised from an old computer extension board. I didn’t have an 0805 120 Ohm resistor, too – and it seems these weren’t so widely used in the days of ISA. Oh well, off to the shop tomorrow. For now, enjoy this image:</p>
<p><img src="/assets/images/2012-01-24-reflow.jpg" alt="dmx-dimmer Master board after etching" /></p>
<p>By the way, I’ve used SMD soldering paste here. The expiration date says August, 2010. Works pretty fine, though. Only had to leak off water that separated.</p>
Retarded power supplyiochrxdtxd2012-01-19T00:00:00+02:00https://wemakethings.net/2012/01/19/retarded-power-supply<p>It was January 18th, 2012, the worldwide SOPA/PIPA protest day. We really wanted to watch a movie. A zombie apocalypse movie. But our test tweeters didn’t have a power adapter, which is probably the reason they ended up in a trashbin. It did have a power connector, but none of our adaptors fit.</p>
<p>Not quite an apocalyptic scenario, but still a distress.</p>
<p>We decided to make a brave dash and solder a pair of wires to where the battery holder is connected (because, believe me, in the face of overwhelming circumstances one never has batteries). Which, of course, didn’t work with a universal switched-mode power supply on the other end, since battery power wasn’t filtered on the PCB.</p>
<p>So we had to bring in another soundsystem. A couple of bigger speakers and an amp. Desperate times call for et cetera.</p>
<p>Next day, though, <em>ioch</em> took a NOKAI phone charger, soldered it to the board, and added a big cap for good measure. I’d post a video of how well it works, but I’d have to put in on YouTube, and doing so might become verboten.</p>
<p><img src="/assets/images/2012-01-19-active-speakers.jpg" alt="Speaker circuit board with installed cap" /></p>
<p>Next week: microwave popcorn and beer in Coca-Cola bottles.</p>
Modifying the LPC1343 devboardmiceuzrxdtxd2012-01-17T00:00:00+02:00https://wemakethings.net/2012/01/17/modifying-the-lpc1343-devboard<p>We’ve been working with Atmel AVRs for quite some time now. All in all, it’s a nice architecture, and I can’t really remember why we decided to try out ARMs, and specifically this Cortex-M3 chip. Maybe it’s their built-in USB bootloader. Or their lower price. Or higher processing power.</p>
<p>Anyway, <a href="http://www.microbuilder.eu/Projects/LPC1343ReferenceDesign.aspx">microBuilder’s LPC1343 devboard</a> looked like just the thing, jumped to <a href="https://www.adafruit.com/products/281">Adafruit</a> to order some, and… it was out of stock! And wouldn’t be available for some time.</p>
<p>Luckily, a few of these chips just happened to be lying around, and the board designs are available. Not so for all the components, though – specifically, the 12 MHz crystal. Which wasn’t hard to replace. Yet, after a few tries to re-route for homebrew manufacture, it became evident there’d be one via too many if one wanted to keep the nice GPIO layout. So it had to be shipped to a PCB manufacturer.</p>
<p>Perhaps this won’t be faster than Adafruit, but at least it’ll be cheaper. Thanks to the fact it’s all open-source (or whatchamacallit). In case you’re interested, here’s the <a href="https://github.com/rxdtxd/LPC1343ReferenceDesign_v1.6">modified version</a> at GitHub.</p>
<p><img src="/assets/images/2012-01-17-lpc1343-pcb-eagle.png" alt="PCB with HC49/S crystal" /></p>