<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
 <channel>
  <title>jes's blog</title>
  <description>This is jes's blog</description>
  <link>http://incoherency.co.uk/blog/</link>
  <lastBuildDate>Sat, 10 Feb 2024 12:00:00 GMT</lastBuildDate>
  <pubDate>Sat, 10 Feb 2024 12:00:00 GMT</pubDate>
  <ttl>1800</ttl>
  <atom:link href="http://incoherency.co.uk/blog/rss.xml" rel="self" type="application/rss+xml"/>
  <item>
   <title>How to read from a TCP socket (but were too afraid to ask)</title>
   <description><![CDATA[You can get surprisingly far, before it bites you, with only a fuzzy and incorrect understanding of how you should read from a TCP socket.
I see this often in (failing) Protohackers solutions.
Once you are over the initial hurdle of reading enough documentation to actually get a TCP session connected,
there are 2 key things you need to understand:]]></description>
   <content:encoded><![CDATA[<p>You can get surprisingly far, before it bites you, with only a fuzzy and incorrect understanding of how you should read from a TCP socket.
I see this often in (failing) <a href="https://protohackers.com/">Protohackers</a> solutions.
Once you are over the initial hurdle of reading enough documentation to actually get a TCP session <i>connected</i>,
there are 2 key things you need to understand:</p>
<p><ol>
<li>TCP gives you a stream of <i>bytes</i>, not packets.</li>
<li><tt>read()</tt> can give you fewer bytes than you asked for.</li>
</ol></p>
<p>If either of those was a surprise: keep reading.</p>
<p><h2>Byte streams</h2></p>
<p>The main misconception people have is that when they're reading from a TCP socket, they are <i>receiving packets</i>.
This is the wrong way to think about it. If you're writing anything higher level than the TCP implementation itself, then you should 
forget about packets. TCP is exposed to you via a pair of <i>byte streams</i>.</p>
<p>Typically both streams are on the same file handle (they have the same file descriptor), but remember there are <i>two</i> underlying
streams: <i>writing</i> puts bytes into the stream that is sent to the other side, and <i>reading</i> gets bytes out of the stream coming
from the other side.</p>
<p>There are a few reasons that people are not immediately disabused of packet-oriented thinking:</p>
<p><ul>
<li>When you learn about networking, you learn about packets, so it is natural to assume that you'll be handling packets.</li>
<li>When you write test programs to send short strings over <tt>localhost</tt>, it probably appears as if every <tt>write()</tt> pops out in a corresponding <tt>read()</tt>.</li>
<li>When you test your server with <tt>netcat</tt>, it appears as if each line is sent as a discrete "packet" because the line-buffering on
<tt>netcat</tt>'s <tt>stdin</tt> means each line doesn't get read by <tt>netcat</tt> until you press enter, and then it all gets sent to the socket at once.</li>
</ul></p>
<p>If you write a program that tries to read "packets", there are a handful of potential issues you can encounter:</p>
<p><ul>
<li>A single read might get less than an entire "packet", your program may think it is a malformed packet, and you'll drop some data and potentially get out of sync with the stream.</li>
<li>A single read might get more than an entire "packet", your program may not notice the extra, and you'll drop some data and potentially get out of sync with the stream.</li>
</ul></p>
<p>Just stop trying to think about packets. The kernel will deal with packets. You will deal with <i>byte streams</i>.</p>
<p>To transfer discrete messages over a byte stream, you need some sort of message encoding. Some simple schemes include:</p>
<p><ul>
<li>Fixed length: every message is the same length, so you know you have a full message when you have that many bytes (see <a href="https://protohackers.com/problem/2">Protohackers problem 2</a>).</li>
<li>Predictable length: not every message is the same length, but you can compute how long the message is going to be based on what type of message it is (see <a href="https://protohackers.com/problem/6">Protohackers problem 6</a>).</li>
<li>Length prefixed: the start of each message tells you how many bytes the message is.</li>
<li>Line delimited: each message is a line of text, so messages are terminated by newline characters (see <a href="https://protohackers.com/problem/1">Protohackers problem 1</a>).</li>
</ul></p>
<p>You can do whatever you want as long as you can work out where the message boundaries are. If you want to transfer structured data I suggest <a href="https://jsonlines.org/">JSON lines</a> for a text format or length-prefixed <a href="https://protobuf.dev/">protobuf</a> for a binary format.</p>
<p><h2>Read semantics</h2></p>
<p>The other misconception is about the semantics of reading from a socket.</p>
<p>Depending on the platform you are using, this could bite you in 2 different ways.
Normally <tt>read()</tt> takes an argument saying how many bytes you want, and then there are 2 common ways for it to work:</p>
<p><ol>
<li>it gives you back any amount of bytes, up to the maximum you gave</li>
<li>it blocks, and keeps reading, until either the end of the stream, or it gives back exactly the number of bytes you asked for</li>
</ol></p>
<p>The actual <tt>read()</tt> system call is "type 1": if there are some bytes available immediately, but not as many as you asked for, you'll 
just get back whatever is available immediately.</p>
<p>C's <tt>fread()</tt> works the second way: it blocks until either the end of the stream, or it has exactly the number you asked for.</p>
<p>Neither of these semantics is necessarily "better" than the other. In the first case, you have to manually make sure you have all the bytes you want (i.e. keep
calling <tt>read()</tt> until you have enough).
In the second case, you have to make sure you don't block the entire program in the course of getting all the bytes you want (e.g. if you want 5 bytes but the kernel only has 1 to give you, <tt>fread()</tt> will block even though <tt>select()</tt> told you the socket was readable).</p>
<p>The following properties are common to both types:</p>
<p><ul>
<li>it can give you less than you asked for (in the case of "type 2": only at the end of the stream)</li>
<li>it can block indefinitely if no data is available (in the case of "type 2": it can also block indefinitely even if <i>some</i> data is available!)</li>
<li>it can give you less than one full packet's worth of data (but you don't care about packets!)</li>
<li>it can give you more than one full packet's worth of data (but you don't care about packets!)</li>
<li>it is <i>not</i> the case that one call to <tt>write()</tt> on the other side will exactly land in one call to <tt>read()</tt> on your side</li>
</ul></p>
<p>Here are some classifications that I'm aware of:</p>
<p><ul>
<li>C: <tt>read()</tt>: type 1, <tt>fread()</tt>: type 2</li>
<li>Perl: <tt>read()</tt>: type 2, <tt>sysread()</tt>: type 1</li>
<li>C#, NetworkStream: <tt>Read()</tt>: type 1, <tt>ReadExactly()</tt>: type 2</li>
<li>Go, io.Reader: <tt>Read()</tt>: type 1, <tt>ReadFull()</tt>: type 2</li>
</ul></p>
<p>If you want to write reliable software, you need to find out what read semantics you're using. Don't just guess.</p>
<p>(Also, for what it's worth, the <tt>write()</tt> system call has the same property as <tt>read()</tt>, in that it
may <i>write</i> fewer bytes than you asked it to; check the return value to know how many bytes were actually
written, and then try again to send the rest).</p>
<p><h2>Half-close</h2></p>
<p>While you're here, I have an axe to grind...</p>
<p>There's one more thing that I want you to know: <a href="https://superuser.com/a/615971">half-close</a>. You remember how we agreed that there
are 2 separate byte streams? Well, corollary to that is that the 2 streams can be closed <i>independently</i>: you can close the stream
you are writing to, even while you still want to read from the other side. If you understand the stream abstraction, this should be natural and good.</p>
<p>Sadly, some "transparent proxies" inadvertently break half-close, by tearing down connections
as soon as they see either of the streams get closed. Please don't do this!</p>
<p>The correct thing to do is to <i>propagate the half-close onwards</i>. If you imagine the TCP session as a pipeline running from the client, through
the proxy, to the server, and then back through the proxy to the client, then it is obvious that the half-close should be propagated on through the
pipeline in the same path that normal messages would take. A half-close shouldn't "jump ahead" of any pending data in the pipeline by closing the
session immediately.</p>
<p><small>(I wanted to draw a neat animation showing a client, a proxy, and a server, with water pipes connecting them, and in the good case, when the flow from the client to the proxy is shut off, all the valves will get shut off one by one, in order, through the whole pipeline, following the last of the flowing water; and in the bad case, as soon as the first valve is shut off, the rest of the pipes all get closed at once and the water they contain is dumped on the ground. But making animations is too much trouble, so please imagine it instead).</small></p>
<p>There is a <a href="https://www.excentis.com/blog/tcp-half-close-a-cool-feature-that-is-now-broken/">blog post from Excentis</a> about
how some NAT proxies break half-close.</p>
<p>Nmap's <tt>ncat</tt> breaks half-close, I have <a href="https://github.com/nmap/nmap/pull/2510">submitted a patch</a> but it has been ignored.</p>
<p>Ngrok breaks half-close, I found out because people tried to solve the <a href="https://protohackers.com/problem/0">Protohackers Smoke Test</a>
using ngrok, and couldn't.</p>
<p>If you're writing any kind of proxy, please implement half-close properly.</p>
<p><h2>Conclusion</h2></p>
<p>It's not that hard to read from a TCP socket, but it is easy to get it subtly wrong if you don't have the right mental models.</p>
<p>And (this is turning into more of a Protohackers ad than intended, but) if you want to test your understanding, you
could try solving some of the <a href="https://protohackers.com/problems">Protohackers problems</a>. If you <i>really</i>
want a challenge: <a href="https://protohackers.com/problem/7">Problem 7</a> has you implement a basic TCP-like protocol on top of UDP.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/reading-tcp-sockets.html</link>
   <guid>http://incoherency.co.uk/blog/stories/reading-tcp-sockets.html</guid>
   <pubDate>Sat, 10 Feb 2024 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>We're not in a simulation</title>
   <description><![CDATA[In this post I'm going to make the case that IF (big if) the universe can be simulated, then
actually running the simulation has no effect on the contents of the universe. Either the universe can be
simulated, in which case we exist within an abstract mathematical structure independent of any actual simulation, or
the universe can not be simulated, in which case we trivially do not live inside a simulation.]]></description>
   <content:encoded><![CDATA[<p>In this post I'm going to make the case that <b>IF</b> (big if) the universe can be simulated, then
actually <i>running</i> the simulation has no effect on the contents of the universe. Either the universe can be
simulated, in which case we exist within an abstract mathematical structure independent of any actual simulation, or
the universe can not be simulated, in which case we trivially do not live inside a simulation.</p>
<p>I first learnt of this idea from a post <a href="https://web.archive.org/web/20221222165025/http://www.billybradley.uk/why-are-things/">Why are things?</a>
by Billy Bradley (which I recommend reading). He talks about a function <b><i>U(P,t)</i></b> which tells you the state of the universe with
parameters <b><i>P</i></b> at time <b><i>t</i></b>. This formalism is useful as an intuition pump, but neither necessary nor sufficient
for explaining the core idea. It's not <i>sufficient</i> because relativity tells us there is no universal "<b><i>t</i></b>", and it's not <i>necessary</i>
because we don't need to define the <i>form</i> of the function in order to talk about what could happen <b>IF</b> a function existed.</p>
<p>I'm also aware that <a href="https://en.wikipedia.org/wiki/Max_Tegmark">Max Tegmark</a> has done a lot of thinking on this, though
I didn't get very far in his book because I got bored of the classical physics long before it got to the interesting part.</p>
<p>The crux of the "mathematical universe hypothesis"
is that <b>IF</b> it is in principle <i>possible</i> to define a mathematical
structure which completely simulates the universe, then the mere "existence" (in an
abstract mathematical sense) of that structure is enough, on it's own, to give the observers within the universe all of their observations.
This means that there is <i>no need</i> for the universe to actually be instantiated anywhere (either "physically" or in a computer).
And, further, that even <i>if</i> the universe were instantiated anywhere in particular, that this
would have no effect whatsoever on the contents of the universe, that we would have no way to find out whether it was being simulated or not,
and that even if the simulation were turned off, we would continue to exist.</p>
<p>The universe doesn't stop when the simulation is switched off for the same reason that arithmetic doesn't end when your calculator
is switched off. The calculator is not <i>creating</i> arithmetic, it's just exposing arithmetical results to someone who exists
outside of arithmetic. Similarly, a universe simulation does not <i>create</i> the universe, it's just exposing the contents of a
universe that was always there. For observers <i>within</i> the universe, the existence of the simulation has no effect.</p>
<p>As far as I'm concerned, the argument is utterly watertight: <b>IF</b> the universe can be simulated, then it doesn't have to be.
I normally find that people either agree straight away, or won't agree no matter how much we discuss it, but their disagreements
don't make any sense and we end up talking past each other.</p>
<p>Please remember the "big if" at the start: <b>IF</b> the universe can be simulated. A counterargument along the lines of "our existence is
special and beautiful and can't be created by mathematics alone" is a claim that the universe <i>cannot</i> be simulated.</p>
<p>I do think the question of whether our universe <i>can</i> be simulated is interesting, of course. But I don't know the answer.
But <b>IF</b> the universe can be simulated, then that neatly answers a number of difficult questions about the nature of reality:</p>
<p><ul>
<li>who created the universe? (nobody, it exists because it can)</li>
<li>what is outside the universe? (in the physical sense: nothing; in the abstract mathematical sense: all other possible mathematical structures)</li>
<li>how did the universe decide when to begin? (it didn't, time as a concept only makes sense from <i>inside</i> the universe)</li>
<li>how does quantum mechanics work? (the many worlds interpretation)</li>
</ul></p>
<p>I think people confuse this argument with a related one: that this "mathematical universe" is an <i>actual</i> explanation of what
our <i>actual</i> universe is made of. We know from the first part that <b>IF</b> the universe can be simulated, then that is enough and you don't
need any more. So the question of whether our actual universe <i>is</i> made this way is really the question of whether our universe
<i>could</i> be made this way. If it could, then by Occam's Razor it is.</p>
<p>I don't know how to find out whether our universe is computable. I expect it probably is, which means I think we <i>do</i> live in a structure
that is made out of mathematics.</p>
<p>To argue that the universe <i>could, in principle</i>, be simulated, and therefore <i>could</i> exist as an unsupported abstract mathematical structure,
but to then argue that actually that is not what is happening and we really "exist within a simulation on a computer" is akin to arguing that the number 42 lives
within your calculator! It is quite obvious that the calculator contains a <i>representation</i> of the number 42, but that is not what
the number 42 actually is. 42 existed before the calculator contained the representation, and it will exist after the calculator no longer contains
it. The calculator is the simulator, and the numbers are the underlying abstract mathematical structure that reality is made out of.</p>
<p><h2>Consciousness</h2></p>
<p>How can we have consciousness if all there is is mathematics? (I don't know!)</p>
<p>We already have enormously complicated mathematical structures that we evaluate on computers and that we don't understand (ChatGPT, for example).
It's not too hard to imagine that a mathematical structure orders of magnitudes more complicated than the observable universe could
contain enough hidden complexity to create consciousness. The fact that consciousness exists and that we perceive anything at all is miraculous. But that we
don't currently know how to model consciousness mathematically doesn't mean it's impossible.</p>
<p><h2>Free will</h2></p>
<p>If every possible path of every possible universe equally "exists" in the mathematical structure of all things, then
we don't really have free will, do we? Probably not. But we also don't "physically exist", and yet we have the <i>experience</i> of physical existence,
and we similarly have the <i>experience</i> of free will.</p>
<p>I maintain that everything after "<b>IF</b> the universe can be simulated, ..." is logically sound, which means if you want to cling on to literal free will, then
you probably have to make the argument that it is mathematically impossible to simulate the universe.</p>
<p><h2>Computational limits</h2></p>
<p>Physical limits on computation don't apply to the simulation hypothesis as I consider it. Any hypothetical simulation would be <i>outside</i> the simulated
universe, so it doesn't have to worry about using more resources than exist within the universe.</p>
<p>But, further, a universe that is "too large to simulate" still <i>exists</i> within the infinite abstract structure of all of mathematics.
It exists just as well even if nobody ever figures out a way to evaluate it using their available resources.</p>
<p><h2>Magic</h2></p>
<p>I'm not saying that mathematics contains a representation of the universe, <i>and that some magic process turns that into a real universe that we can
experience</i>. I'm saying that the magic process doesn't need to exist. Any "magic", if you want to call it that, is in the structure itself.</p>
<p><h2>The anthropic principle</h2></p>
<p>The abstract structure of all structures is obviously infinite, and contains infinitely many possible universes. Isn't it phenomenally unlikely
that we find ourselves not just in a universe in which observers <i>can exist in principle</i>, but that we find ourselves existing <i>as observers ourselves</i>?</p>
<p>Every arrangement of particles that can not observe, can not observe. The fact that we can observe anything at all means we have already selected ourselves
into the subset of universes in which observation is possible, and in which we are observers.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/simulation.html</link>
   <guid>http://incoherency.co.uk/blog/stories/simulation.html</guid>
   <pubDate>Fri, 02 Feb 2024 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The watch project</title>
   <description><![CDATA[My quest at the moment is to try to make a mechanical watch. Specifically I want to make
the movement. I'm not interested in buying a bunch of parts and assembling a watch.
I'm also not interested in cloning a standard movement, I have my own design in mind.]]></description>
   <content:encoded><![CDATA[<p>My quest at the moment is to try to make a mechanical watch. Specifically I want to make
the movement. I'm not interested in buying a bunch of parts and <i>assembling</i> a watch.
I'm also not interested in cloning a standard movement, I have my own design in mind.</p>
<p><h2>Concept</h2></p>
<p>The watch will be about 50mm in diameter, it will only have one hand (the hour hand, obviously),
it will be accurate to within 1%, it will probably tick below 10000 beats per hour (very slow for a watch),
it will run for almost 12 hours on a single winding, and you'll wind it up
and set the time by rotating the outside of the case in the plane of the watch.</p>
<p>Yes, 1% is very poor, almost 15 minutes per day. But I'm not an actual watchmaker, so... lower those expectations.</p>
<p>And, yes, although niche, there <i>is</i> precedent for one-handed watches. And for my purposes it is ideal
because the watch isn't going to be accurate enough for minutes to be worth looking at anyway, and I have
an ingenious design (if I say so myself) for setting the time that only works if you don't have a minute hand.</p>
<p>I have made a mockup (with no actual works, just ratchets) to show what I mean:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4714"><img src="https://img.incoherency.co.uk/4714/thumb"></a></p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/Qrzgl8y2wXU" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>And this is a CAD mockup of a layout for the insides (that I'm not going to use):</p>
<p><a class="img" href="https://img.incoherency.co.uk/4799"><img src="https://img.incoherency.co.uk/4799/thumb"></a></p>
<p>The large circle around the outside is the "barrel" and will contain the coiled up mainspring,
which provides the power to drive the watch.
You wind it up by rotating the outside clockwise, which coils the mainspring tighter. The mainspring pushes
against the inside of the barrel, which has the gear teeth around its inside, which then drives the gear train.</p>
<p>The outer barrel will have a ratchet coupling it to the rest of the movement, so that it is allowed
to turn clockwise (when you wind it) but will not be driven backwards by the spring tension.</p>
<p>The hand is mounted directly on the inner part of the barrel.
This means the only job of the movement is to slow down the rotation of the barrel so that it completes 1 revolution in 12 hours.</p>
<p>To set the time, you need to turn the outer barrel <i>anticlockwise</i>. This will apply torque to the entire
movement, through the ratchet that is preventing the outer barrel from unwinding. The movement itself is held into
the case of the watch with a second ratchet, which allows it to turn anticlockwise only.</p>
<p>I think this is quite an elegant solution for a one-handed watch. We don't need any actual mechanism to allow
the setting of the hand, because we just rotate the entire movement until the hand shows the right time!</p>
<p>The main caveat is that you need the movement to be held in the case with quite a fine ratchet, because you can only
set the time as precisely as you can rotate the movement.</p>
<p>The real problem in making a watch is making an escapement. If you can make an adequate escapement, the rest of
the watch will make itself. (Or so I tell myself).</p>
<p>One of the biggest accuracy problems in a watch is that the torque from the mainspring reduces as the spring unwinds. This means
your escapement needs to be very good, compared to what you could get away with in a weight-driven clock for example.</p>
<p><h2>Fusee</h2></p>
<p>One historical technique is to use a coned pulley called a <a href="https://en.wikipedia.org/wiki/Fusee_(horology)">fusee</a>
so that the leverage of the spring is increased as its pulling force is decreased, to cancel out the effect.</p>
<p><a class="img" href="https://img.incoherency.co.uk/5044"><img src="https://img.incoherency.co.uk/5044/thumb"></a><br>(image from Wikipedia)</p>
<p>I don't want to use a fusee. It is bulky and difficult to make, and it becomes unnecessary if the escapement is good 
enough. The only reason they were used in the olden days is because they didn't have better ideas on how to make escapements.</p>
<p><h2>My simple escapements</h2></p>
<p>My first attempts at making escapements were essentially planar analogues of the <a href="https://en.wikipedia.org/wiki/Verge_escapement">verge escapement</a> used in historical clocks and watches. (Incidentally, if you want to see a verge escapement operating,
you should visit the <a href="https://en.wikipedia.org/wiki/Salisbury_Cathedral_clock">clock at Salisbury Cathedral</a>, it is thought to have been made around 1386 and is still running today, albeit with
some parts remanufactured in the 1900s).</p>
<p>I wrote an <a href="https://incoherency.co.uk/escapement/">escapement simulator</a> to help me come up with escapements
that might plausibly work. Just laying out the geometry of the escapement is a lot harder than it sounds, it is very easy to make designs that jam up,
or don't provide any impulse to the balance.</p>
<p>Here's an example of the sort of thing I was hoping to use:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4607"><img src="https://img.incoherency.co.uk/4607/thumb"></a></p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/EpGQYWlIT5E" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>It has 2 pins on the balance wheel, and the escape wheel teeth hit these pins to alternately push the balance wheel back and
forth.</p>
<p>This is a very poor escapement because the tick rate changes too much as the drive torque changes. This is because the rate at
which the balance wheel accelerates and decelerates purely comes from the escape wheel. An improvement is to add a balance spring,
but I spent quite a lot of time experimenting with this sort of thing and I still couldn't work out how to make it accurate enough to work
without a fusee.</p>
<p><h2>Lever escapement</h2></p>
<p>So then I moved on to trying to make a simplified version of the <a href="https://en.wikipedia.org/wiki/Lever_escapement">lever
escapement</a>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/5045"><img src="https://img.incoherency.co.uk/5045"></a><br>(image from Wikipedia)</p>
<p>The (Swiss) lever escapement is the standard escapement used in almost all mechanical watches for the
last 100 years or more, however it has quite a lot of features that need to be formed very precisely in order for it to
work correctly.</p>
<p><h2>Pin-pallet escapement</h2></p>
<p>In 1867, someone called Georges Frederic Roskopf invented the <a href="https://en.wikipedia.org/wiki/Pin-pallet_escapement">pin-pallet escapement</a> as a way to produce lever escapements more cheaply, to use in his "proletarian watch", the first commercially-produced
watch for the working classes.  
You can read more about this watch in <a href="http://www.watkinsr.id.au/buffat.html">History and Design of the Roskopf Watch</a> (<a href="https://incoherency.co.uk/interest/roskopf.pdf">mirrored</a>), originally by Eugene Buffat in 1914, translated to English by <a href="http://www.watkinsr.id.au/index.html">Richard Watkins</a> in 2007. I first learnt of it from videos by <a href="https://www.youtube.com/watch?v=KdQA8bHxzJo">Jacques Favre</a>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/5046"><img src="https://img.incoherency.co.uk/5046/thumb"></a><br>(image from the Watkins PDF)</p>
<p>The pin-pallet escapement is essentially the same as a lever escapement, except that the pallet jewels and impulse jewel are replaced with
steel pins. This suits me because I can cut steel pins to length, but I can't (yet!) grind jewels to precise shapes.</p>
<p>However the pin-pallet escapement still has a complicated "guard" arrangement (to the right in the diagram). In normal
operation none of the guard surfaces touch each other, so it is tempting to omit them. The issue is that if the watch is shaken,
then the lever can unlock from the escape wheel and get "banked" the wrong side of the impulse pin, causing the watch to slam to
a halt when the impulse pin swings back a fraction of a second later. The guard pin prevents the lever from moving except when it is lined up with the impulse pin.</p>
<p><h2>Captive lever escapement</h2></p>
<p>My idea was to make the impulse pin <i>captive</i> in the lever.
This way even if the watch is shaken and the escapement unlocks prematurely, the lever can never get the wrong side of the pin. My first
design with a lever was something like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4640"><img src="https://img.incoherency.co.uk/4640/thumb"></a></p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/1olZRxL97JM" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>And it worked, to an extent. It was a marked improvement over my previous designs because it allowed an increase in amplitude (e.g. 10&deg; of lever movement are amplified to 40&deg; of balance wheel movement), but it has 2 significant drawbacks compared to a real
lever escapement:</p>
<p><ol>
<li>it does not allow the balance wheel to detach from the lever</li>
<li>it does not support amplitudes over 180&deg;</li>
</ol></p>
<p>Having the escapement "lock" and allow the balance wheel to swing free from the lever is what allows the balance wheel to keep good
time, free from the influence of the drive torque from the escape wheel. And the more amplitude your balance wheel can have, the
more time it spends detached, and the less influence the drive torque has on the tick rate.</p>
<p>My design did not support amplitudes over 180&deg; because to do so would cause the lever to pass through the shaft of the
balance wheel (yes, we're on <a href="https://en.wikipedia.org/wiki/Shaft_passer">shaft passers</a> again). But I persisted with it,
because it was better than any of my other ideas.</p>
<p>I added a locking feature to the escape wheel, and this gave another marked improvement in accuracy, enough to convince me that
the watch <i>might</i> work, and I set about building a metal version at final watch scale. I've kind of been working on this metal
model on and off for almost 2 months now and I still haven't finished it, but this is what I have at the moment:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4948"><img src="https://img.incoherency.co.uk/4948/thumb"></a></p>
<p>There is a barrel to wrap a tiny thread around, connected to a gear that will drive the escape wheel, and there is a tiny
pallet fork with 0.5mm pallet pins, connected to the balance wheel that has a (very poor) homemade hairspring.</p>
<p>And then one day I had the idea that instead of making all the shafts the same length, I could make the shaft that holds the balance
wheel shorter, and let the lever arm pass <i>over the end</i> of the shaft, like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4959"><img src="https://img.incoherency.co.uk/4959/thumb"></a></p>
<p>Making plates at different heights is a relatively standard idea in watchmaking (a plate that is only supported on one end is called a "cock", so this is
a "balance cock"), it just took a mental leap for me to actually perceive that it was something
that I could apply. I had been labouring under the misapprehension that for simplicity I needed all of my parts to be pivoted into the same
plates.</p>
<p>I made some minor improvements to the pallet and escape wheel geometry, and mainly to the shape of the slot to make the impulse pin
more free, and this is my current best escapement model:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/NW2_8KEqEEE" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>It shows amplitudes of well over 180&deg;! Great success. And the tick rate hardly varies even as the
amount of drive torque changes by a factor of 4 (from 1 to 4 "nuts" here):</p>
<p><a class="img" href="https://img.incoherency.co.uk/5007"><img src="https://img.incoherency.co.uk/5007/thumb"></a></p>
<p>(Note that in the 5 and 6 nut cases, the amplitude was so high that the impulse pin was hitting the balance
cock and bouncing back, so the rate increased).</p>
<p>This model was at about 3x the largest scale that I think might fit inside a 50mm watch. Around this time I was experimenting
with using a 0.25mm nozzle to 3d print small parts, so I tried to 3d print a version of this escapement at 1x scale.</p>
<p>I have this, which is not quite working yet (the hairspring is from an assortment of clock hairsprings I bought, I didn't
wind this one myself):</p>
<p><a class="img" href="https://img.incoherency.co.uk/5030"><img src="https://img.incoherency.co.uk/5030/thumb"></a></p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/_NVsvdUncnI" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>So the current status on the watch project is that the 3x-scale 3d-printed escapement works well enough to satisfy me, the 1x-scale
3d-printed escapement doesn't quite work yet, but it feels close, and the 1x-scale metal escapement only needs a few more parts
(pinion for the escape wheel, something to hold the hairspring to the frame).</p>
<p><h2>Machining</h2></p>
<p>Since I'm not a real watchmaker, I don't have most of the skills that a watchmaker would use to make watch parts, so I have a lot
to learn in that regard. But I'm also not
<i>constrained</i> to the techniques that a watchmaker would use. As long as I make working parts, it doesn't
matter how they get made.</p>
<p>I have <a href="https://www.youtube.com/watch?v=LPaPfc_RRQM">a video clip</a> showing how I made my metal
escape wheel. The short version is I used a 0.6mm end mill in my <a href="https://incoherency.co.uk/blog/stories/6040-cnc-grbl-arduino.html">CNC router</a>
to machine the shape of the escape wheel onto the end of a brass bar, then parted the finished escape wheel off the bar using the
lathe.</p>
<p><h2>Clocks</h2></p>
<p>Surprisingly, the watch project has led to a greater interest in <i>clocks</i> rather than watches. I don't know how
much of this is just that clocks are so obviously much easier to make.</p>
<p>I enjoyed visiting the <a href="https://incoherency.co.uk/blog/stories/harrison-clocks.html">Harrison clocks</a> at Greenwich.</p>
<p>I bought a handful of old clock books from a secondhand bookshop in Dawlish, one of them was "How to make an electric clock"
by R. Barnard Way,
which suggests a design that I think is called a "Hipp toggle". It uses a pendulum to keep time, but the pendulum is given an electromagnetic
kick whenever the amplitude gets too low. But I thought the idea of using mains electricity to kick a pendulum is foolish,
when you should be able to use the 50 Hz sine wave to count time directly, so I designed
and built a <a href="https://www.youtube.com/watch?v=yroDFrE3mJQ">stepper motor clock</a> driven directly off 50 Hz from the wall.</p>
<p>I also experimented with what I call the <a href="https://www.youtube.com/watch?v=mRFbPuerHZ8">Scotch Yoke escapement</a>. It has no
escape wheel as such, instead the pendulum is driven by a
<a href="https://en.wikipedia.org/wiki/Scotch_yoke">Scotch yoke</a>. It will be a poor timekeeper for the same reason that
my first watch escapement designs were poor: the pendulum is never decoupled from the drive torque, so more torque will always
make it run faster. And in fact it is even worse because the pendulum in the Scotch Yoke escapement <i>always has the same amplitude</i>. But I kind of want to make a clock with it anyway.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/the-watch-project.html</link>
   <guid>http://incoherency.co.uk/blog/stories/the-watch-project.html</guid>
   <pubDate>Thu, 23 Nov 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Interesting features of John Harrison's sea clocks</title>
   <description><![CDATA[I recently got to see John Harrison's sea clocks at the Royal Observatory at Greenwich.
I recommend visiting if you get the chance. This post is about some of the interesting things
I observed.]]></description>
   <content:encoded><![CDATA[<p>I recently got to see John Harrison's sea clocks at the Royal Observatory at Greenwich.
I recommend visiting if you get the chance. This post is about some of the interesting things
I observed.</p>
<p><h2>Longitude</h2></p>
<p>In case you don't already know the story of John Harrison, the short version is this:</p>
<p>In 1714, the British government <a href="https://en.wikipedia.org/wiki/Longitude_Act">offered a prize</a>
for anyone who could invent a "practical and useful" way to calculate
longitude at sea. It was already known that you could do this with a clock (the difference between solar
noon on the ship and solar noon at some reference location tells you your longitude difference from the reference location).
However it was not known how to make a clock sufficiently accurate onboard
a ship, due to the temperature and humidity variations and the movements of the ship. John Harrison
solved the problem, although the Board of Longitude didn't like his solution
and he had great difficulty collecting the prize money, eventually receiving most of the prize at the age of 80,
having spent almost his entire adult life working on the project.</p>
<p>(The ultimate dream for any creative person has to be to find a project that you love working on the way John Harrison
loved working on clocks. I'm still searching.)</p>
<p>If you want the long version of the Longitude story, check out some of the resources I link at the bottom of this post.</p>
<p><h2>Materials</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/4968"><img src="https://img.incoherency.co.uk/4968/thumb"></a></p>
<p>There appears to be some porosity in a couple of the brass plates in H1. It's hard to see clearly because
the clock is inside a glass cabinet which prohibits close inspection. It could conceivably be some other
sort of damage.</p>
<p>But if it <i>is</i> porosity, then that you would use such
poor materials in such an important project suggests that high-quality materials were hard to come by
in Harrison's time, or were very expensive. Nowadays we simply take for granted that we can buy sheets
of metal that don't have voids in the middle!</p>
<p><h2>Anti-friction wheels</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/4967"><img src="https://img.incoherency.co.uk/4967/thumb"></a></p>
<p>The wheels you're looking at here are not <i>gears</i>, and they don't drive anything. These are <i>anti-friction wheels</i>,
a strange type of bearing.</p>
<p>The clocks use anti-friction wheels for shafts that require particularly low friction. You can read in
<a href="https://soptera.files.wordpress.com/2013/10/csm-translation.pdf">"Concerning Such Mechanism"</a> (<a href="https://incoherency.co.uk/interest/csm-translation.pdf">mirrored</a>) that Harrison takes the reduction of sliding friction
very seriously. Anti-friction wheels are one method of achieving this.</p>
<p>Instead of having the shaft riding directly in plain bearings, the shaft instead sits on a pair of wheels
at each end, and rolls against the wheels, and it is these wheels which ride in plain-bearing pivots.
The advantage is that you have
geared the rotation down by the ratio of the wheel diameter to the shaft diameter (a ratio of 20 or more)
by the time it reaches the plain bearings, with a corresponding reduction in sliding friction.</p>
<p>It looks like there is also a lignum vitae bush that will prevent the shaft
from falling off the wheels (if it is shaken too violently for example), but in normal operation the wooden bush
will not touch the shaft at all.</p>
<p>For parts that oscillate, a complicated version of these anti-friction wheels is used,
where instead of building the entire anti-friction wheel, only the part that engages the shaft needs to exist.</p>
<p>Maybe in this recording of H2 you can see the movement in the rectangular aperture as the shaft oscillates back and forth:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4971"><img src="https://img.incoherency.co.uk/4971/thumb"></a></p>
<p>It's important to remember that the lower long edge of this rectangular aperture (which is actually a large radius
rather than a straight line) is the <i>bearing surface</i> of the shaft. It doesn't just happen to <i>touch</i> the
shaft, it is what <i>decides</i> where the shaft sits. It bears the weight of the shaft. At each end of the
shaft there are two of these. Obviously the foreground one is easiest to see, but you can kind of see one
just behind it, at about 90 degrees to the first.</p>
<p>The part that touches the shaft is on the end of a long arm so that the rotation in the arm's pivot is almost
nothing.</p>
<p>Here's a picture of the other end of a similar arrangement on H1:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4970"><img src="https://img.incoherency.co.uk/4970/thumb"></a></p>
<p>It took me a little while to work out what the knobs are at the bottom of this picture: they're <i>counterweights</i>
for these anti-friction wheel-portions. You can imagine that if there wasn't a counterweight then the weight of
the portion of wheel that is present will cause itself to fall down.</p>
<p>A counterweight alone is not quite enough, because while it will make the arm stable, it will be stable in <i>any</i>
position, so a harsh jolt could still knock it clear of the shaft. For this reason there is also a spring to return
the arm to its centre position.</p>
<p>What an enormous amount of work to go to just to create a pivot for a shaft!</p>
<p><h2>Lantern pinions with rollers</h2></p>
<p>A <i>lantern pinion</i> is a type of gear where the teeth are made out of pins suspended between
two plates. Here's an example of a "normal" lantern pinion, from <a href="https://richard.burtons.org/2014/12/14/a-new-lantern-pinion/">Richard's
Stuff</a> (not from Harrison):</p>
<p><a class="img" href="https://img.incoherency.co.uk/4974"><img src="https://img.incoherency.co.uk/4974/thumb"></a></p>
<p>Not content with the friction properties of an ordinary lantern pinion, John Harrison put lignum vitae rollers
on the pins, so that the friction can be further reduced:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4972"><img src="https://img.incoherency.co.uk/4972/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4973"><img src="https://img.incoherency.co.uk/4973/thumb"></a></p>
<p><h2>Temperature compensation</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/4961"><img src="https://img.incoherency.co.uk/4961/thumb"></a></p>
<p>The temperature compensation mechanisms of the clocks are the hardest part for me to understand. The picture
above is from H1. You can see there is a structure similar to that of a <a href="https://en.wikipedia.org/wiki/Gridiron_pendulum">gridiron pendulum</a> (also a Harrison invention) lying horizontally near the middle. A gridiron pendulum is designed so that its endpoints remain the same distance apart regardless of thermal expansion,
but in this case I expect it is wired up "backwards" so that it expands much <i>more</i> than normal thermal expansion
would account for.</p>
<p>The end of the backwards-gridiron presses against a lever which magnifies the expansion further, which then presses
against another lever to magnify it even further, a couple of times, until it eventually adjusts the stops for the balance
springs. I think the idea is that to prevent the clock from running at a different rate in different temperatures, the
balance spring is forced to stop at a different point.</p>
<p>I have no idea how well it works, but it occupies nearly 50% of the volume of the clock, so Harrison obviously
thought it important.</p>
<p><h2>Shaft-passing</h2></p>
<p>There is an interesting feature on H3:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4975"><img src="https://img.incoherency.co.uk/4975/thumb"></a></p>
<p>There are stationary pillars that stand <i>in between</i> the spokes of the balance wheels! This is crazy! Why do this?</p>
<p>In the best case it complicates assembly. In the worst case the balance wheel crashes into the pillar.</p>
<p>John Harrison spent <i>19 years</i> working on this clock, so I guess the answer is just that he did it because he can.</p>
<p>It reminds me of the apocryphal "<a href="https://en.wikipedia.org/wiki/Shaft_passer">shaft passer</a>" device, to be
specified wherever the spokes of a wheel need to pass through a shaft.</p>
<p>(Incidentally, I also have some thoughts on how a shaft passer should be constructed, and intend to make one one day.
See <a href="https://www.youtube.com/watch?v=dmPgTDs9FRo">this video</a> with only 2000 views for the best example
I've seen so far, although it is not actually a shaft passer per se).</p>
<p><h3>Resources</h2></p>
<p>Some of the best resources for learning about John Harrison, his clocks, and the Longitude problem, include:</p>
<p><ul>
<li><a href="https://www.amazon.co.uk/John-Harrison-Timekeepers-Rupert-Gould/dp/0905555163">John Harrison and His Timekeepers</a> by Rupert Gould, who restored the clocks in the first half of the 20th Century</a></li>
<li><a href="https://redfernanimation.com/the-harrison-timekeepers/">Animations of the Harrison Timekeepers</a> by John Redfern</li>
<li><a href="https://www.amazon.co.uk/Longitude-Genius-Greatest-Scientific-Problem/dp/0007214227/ref=sr_1_1?crid=3S79FIIEJ3W4A&keywords=longitude+dava+sobel&qid=1699828408&sprefix=longitude+dava+sobel%2Caps%2C79&sr=8-1">Longitude: The True Story of a Lone Genius Who Solved the Greatest Scientific Problem of His Time</a> by Dava Sobel</li>
<li><a href="https://www.youtube.com/watch?v=T-g27KS0yiY">The Clock That Changed the World</a> with Adam Hart-Davis</li>
<li>"<a href="https://www.youtube.com/watch?v=LHvt48S9l4w">Longitude</a>" the dramatic film adaptation</li>
<li>"<a href="https://soptera.files.wordpress.com/2013/10/csm-translation.pdf">Concerning Such Mechanism</a>" (<a href="https://incoherency.co.uk/interest/csm-translation.pdf">mirrored</a>): a "translation" by David Heskin, of a work by John Harrison</li>
<li>"<a href="https://www.youtube.com/watch?v=N-wm39a6r_k">Making a wooden grasshopper clock according to John Harrison's principles</a>" by P. Hefetrueb</li>
</ul>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/harrison-clocks.html</link>
   <guid>http://incoherency.co.uk/blog/stories/harrison-clocks.html</guid>
   <pubDate>Sun, 12 Nov 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Incongruous technologies redux</title>
   <description><![CDATA[Good news: I have worked out why my incongruous technologies are
incongruous: it's because of software!]]></description>
   <content:encoded><![CDATA[<p>Good news: I have worked out why my <a href="https://incoherency.co.uk/blog/stories/incongruous-technologies.html">incongruous technologies</a> are
incongruous: it's because of software!</p>
<p>I just watched <a href="https://www.youtube.com/watch?v=6Nt7xLAfEPs">an excellent documentary</a> on mechanical automata.
It includes demonstrations (among several other excellent examples) of "The draughtsman" and "The writer"
built by <a href="https://en.wikipedia.org/wiki/Jaquet-Droz_automata">Pierre Jaquet-Droz</a> in the late 1700s.
These automata are little mechanical boys that can draw pictures and write text, respectively.</p>
<p>I wrote in the previous post on this topic that we don't have any applications, beyond watchmaking, for systems of tiny springs and
gears. But these automata are excellent examples to the contrary. Just look at the back of "The writer":</p>
<p><a class="img" href="https://img.incoherency.co.uk/4934"><img src="https://img.incoherency.co.uk/4934/thumb"></a></p>
<p>In particular, note the large circle at the bottom: this is how the device is <i>programmed</i>. Each of the shapes
loaded around the perimeter of this circle has a different height, and the height changes how far the stack of discs
in the middle of the boy is raised up, and the height that this stack is raised up decides the set of discs that are selected,
and the set of discs that are selected decides the letter that the writer will draw. The whole stack of discs rotates,
each of the boy's "muscles" follows its selected disc, and the boy writes the text that you've programmed in to him. Superb.</p>
<p>This is exactly the kind of stuff I thought we didn't have, and they were making it 250 years ago!</p>
<p>So why don't we make stuff like this today?</p>
<p>Well... imagine how <i>you</i> would go about designing "The writer" if you were designing him today. Unless you're crazy,
or have a very specific and unusual set of skills, or want to do it for historical interest instead of practical purposes, you
wouldn't do it like this. You'd have a dinky little microcontroller and 3 stepper motors and you'd save yourself
a load of time and money and effort and frustration.</p>
<p>The reason people used to make stuff like this isn't that they had tapped into remarkable technology that we're
under-utilising now. It's that they didn't have software! If Pierre Jaquet-Droz could have solved his problems
using software he would have done so, but he didn't have software so he had to make up for it with incredible ingenuity
and hard work.</p>
<p>So the real question isn't "why don't we make better use of tiny gears and springs?" It's "why do we still
use gears and springs at all?".</p>
<p>And this also gives us an answer as to why we don't make better use of IC fabs: there's no <i>reason</i> to make anything
other than integrated circuits, because integrated circuits are just a substrate for software, and software gets
you everything you want.</p>
<p>So why <i>do</i> we still use gears and springs at all? Why don't we do
<i>literally</i> everything with software? At some point (for the time being!) we still need to interact
with the physical world. For our digital clone of "The writer" boy to actually write on actual paper, he needs to actually move
an actual pen, and to do that he'll need motors and probably gearboxes.</p>
<p>But the kinds of springs and gears that
are involved there are substantially simplified compared to what Pierre Jaquet-Droz was working with. Instead of
making bespoke gears and springs for every application, we make generic gears and springs, and control them
with bespoke software, because software is quick and easy to make and mechanical systems aren't.</p>
<p>Obviously, in the long-term, we're all going to be living our lives in permanent VR (to the extent that experiencing
the world through the filters of our senses and brain is not <i>already</i> a kind of permanent VR). And then we won't be needing any more motors.</p>
<p>(Also, note that the kind of "pen" that Jaquet-Droz uses is not what we would recognise today, because actual pens <i>hadn't been invented</i>
back then. So "The writer" has to automatically <i>dip his quill in the ink</i> periodically while he does his writing! And
this is all orchestrated with gears and springs and cams and shafts).</p>
<p>Anyway, the short answer as to why we aren't making maximal use of tiny mechanical systems, or of IC fab technology,
is because we can make use of software to solve the same problems faster, cheaper, and easier. It might be interesting
to see how that can be extended further: next time you encounter a tiny bespoke mechanical system, maybe
imagine how it could be replaced with a generic mechanical system controlled by software.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/incongruous-technologies-redux.html</link>
   <guid>http://incoherency.co.uk/blog/stories/incongruous-technologies-redux.html</guid>
   <pubDate>Sun, 05 Nov 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>A self-aligning Boggle board</title>
   <description><![CDATA[Earlier this year Charlie challenged me to make a Boggle board that always leaves
the letters upright, and this week I have succeeded.]]></description>
   <content:encoded><![CDATA[<p>Earlier this year <a href="https://charlie.ht/">Charlie</a> challenged me to make a Boggle board that always leaves
the letters upright, and this week I have succeeded.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4904"><img src="https://img.incoherency.co.uk/4904/thumb"></a></p>
<p>I have a video demo here:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/ykt3Z8U7-CI" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>And you can get the files at <a href="https://www.printables.com/model/625901-self-aligning-boggle">https://www.printables.com/model/625901-self-aligning-boggle</a>
if you want to print one yourself.</p>
<p>I initially experimented with <a href="https://www.youtube.com/watch?v=pbfjU9Zkcgw">a system of gears</a>
that would rotate the cubes into place, but gave up because I couldn't convince myself that it was going to work.
But last week I stumbled across the idea of solving the problem purely using the shape of the cube, with no
active mechanism involved.</p>
<p>The only "active" part is that you have to shake it to get the cubes to line up, but you already have to shake it
to shuffle the cubes anyway, so I think this is quite an elegant solution.</p>
<p>The cubes are made out of shapes that are like a circle on three corners but a square on the fourth:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4907"><img src="https://img.incoherency.co.uk/4907/thumb"></a></p>
<p>With a ramp around the edge of the pockets, to encourage the cubes to fall into place under gravity:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4908"><img src="https://img.incoherency.co.uk/4908/thumb"></a></p>
<p>They don't fall into the pockets perfectly every time, but the mesh lid makes it easy to tell if there are any mis-aligned
cubes, and you can jiggle it a bit until they fall into place.</p>
<p>I have put steel rods into the centres of the cubes to add weight. This helps a lot with making them fall into place instead of
sitting on the edges of the hole, and it also prevents them from bouncing out of their pockets again when jiggling.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4892"><img src="https://img.incoherency.co.uk/4892/thumb"></a></p>
<p>I need a better way to paint letters on to parts like these.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4900"><img src="https://img.incoherency.co.uk/4900/thumb"></a></p>
<p>Normally I try to make areas that I need to colour stick <i>out</i>, and then
it is easy to drag a Sharpie over the high spots, but in this case if the letters stuck out they would
interfere with the shape of the cube, so they need to be set <i>in</i> instead. Painting them is very tricky because the paint likes
to run in the layer lines, and it is easy to accidentally bump the brush against the edges of the hole. If you have a multi-material machine
you could do a much better job.</p>
<p>The mesh lid is very satisfying, it is made out of 20% gyroid infill, with a "modifier cube" in PrusaSlicer to set 0 top layers
and 0 bottom layers. It feels surprisingly springy.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4903"><img src="https://img.incoherency.co.uk/4903/thumb"></a></p>
<p>I have submitted the design for my self-aligning Boggle board to <a href="https://spark.hasbro.com/">Spark Hasbro</a> (Hasbro are the makers of the official
Boggle game). Spark Hasbro seems to be designed for kids to send crayon drawings of their toy ideas, but maybe
they will find self-aligning Boggle interesting.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/self-aligning-boggle.html</link>
   <guid>http://incoherency.co.uk/blog/stories/self-aligning-boggle.html</guid>
   <pubDate>Wed, 25 Oct 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The Douzieme gauge</title>
   <description><![CDATA[In this post I'm going to explain what a Douzieme gauge is, show you how I made one myself,
and propose some alternative designs for higher precision.]]></description>
   <content:encoded><![CDATA[<p>In this post I'm going to explain what a Douzieme gauge is, show you how I made one myself,
and propose some alternative designs for higher precision.</p>
<p>Mine looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4750"><img src="https://img.incoherency.co.uk/4750/thumb"></a></p>
<p><h2>What is a Douzieme gauge?</h2></p>
<p>"Douzieme" is a French word meaning "one twelfth". As a historical unit, the Douzieme refers
to 1/12 of a <a href="https://en.wikipedia.org/wiki/Ligne"><i>ligne</i></a>,
which is about 2.256mm. Apparently the "ligne" is still used in French and Swiss watchmaking.</p>
<p>A <i>Douzieme gauge</i> is a traditional watchmaker's measuring tool. Here's a picture I found online:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4690"><img src="https://img.incoherency.co.uk/4690/thumb"></a></p>
<p>The legs are squeezed together by hand (against the spring pressure), which opens the jaws. The jaws
are placed around the object to be measured, and then the legs are released, allowing the spring to push the
legs back open, making the jaws close.
When the jaws close around the object, the dimension can be read off the scale. The scale is (say) 5x as
far away from the pivot as the jaws are, so the length at the jaw is amplified by a factor of 5 at the scale,
which is how the device achieves its precision.</p>
<p>What a simple and ingenious idea! This inspired me to make one for myself.</p>
<p><h2>Making a Douzieme gauge</h2></p>
<p>I made this one:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4750"><img src="https://img.incoherency.co.uk/4750/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/4749"><img src="https://img.incoherency.co.uk/4749/thumb"></a></p>
<p>Pictured here measuring the thickness of a watch gear at 0.55mm.</p>
<p>I don't actually work in douziemes, so I graduated the scale in 0.1mm increments (which are 0.5mm apart
in reality, because of the 5:1 ratio).</p>
<p>I opted to make the spring out of stainless steel wire, instead of integrating it into one of the parts,
because I made my parts out of mild steel and mild steel springs don't work very well. (For that matter,
mild steel <i>jaws</i> probably won't work very well, but I have a solution for that).</p>
<p>I started by designing this in FreeCAD:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4701"><img src="https://img.incoherency.co.uk/4701/thumb"></a></p>
<p>I made both of the main parts out of 3mm mild steel sheet:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4721"><img src="https://img.incoherency.co.uk/4721/thumb"></a></p>
<p>One of them was made on the CNC milling machine, and one was made by hand on the bandsaw, because I wanted to
compare how long each process took. It was 47 minutes for the CNC part and only 26 for the one I did by hand,
but I had very <a href="https://www.youtube.com/watch?v=4tJ4udSikAg">suboptimal cutting</a> on the milling machine,
and the one I did by hand is less faithful to the intended dimensions and needed more cleaning up with files,
so it's swings and roundabouts really.</p>
<p>And I did use the milling machine, even on the handmade part, to cut the step around the pivot. This is the clamping
setup I used:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4724"><img src="https://img.incoherency.co.uk/4724/thumb"></a></p>
<p>Not great but it was adequate. I should really get a strap clamp set.</p>
<p>I also made a clamping washer on the lathe, and shortened an M4 allen screw to hold the parts together at the pivot.</p>
<p>Then I came to making the spring. My first thought was to make a simple bend in the stainless steel wire and put some holes
in the sides of the legs to accept it, but it became obvious that that wasn't going to work (the spring would rotate freely
instead of lying in the plane of the tool).</p>
<p><a class="img" href="https://img.incoherency.co.uk/4726"><img src="https://img.incoherency.co.uk/4726/thumb"></a></p>
<p>So instead I copied the design from a pair of circlip pliers. I wrapped the stainless steel wire around a screwdriver
a few times to form the coil, and hammered the ends over in the vice to make the ends. It works surprisingly well.</p>
<p>I cut out the shape for the scale according to the CAD model, but realised it was not going to work because it is too short:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4727"><img src="https://img.incoherency.co.uk/4727/thumb"></a></p>
<p>The pointer is off the end of the scale.</p>
<p>I think probably one of the pieces ended up with the jaw slightly shorter than intended, which means the jaws close
closer together, which means the legs end up further apart.</p>
<p>So instead I made a series of paper scales, designed in <a href="https://librecad.org/">LibreCAD</a>, to get the perfect alignment:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4745"><img src="https://img.incoherency.co.uk/4745/thumb"></a></p>
<p>It is definitely worth going through several paper iterations to make sure the scale is correct.</p>
<p>I found making the scale in LibreCAD to be very laborious, and then I found that LibreCAD doesn't
even have any CAM capabilities, despite the homepage stating that "LibreCAD started as a project to
build CAM capabilities into the community version of QCad" - it seems it still doesn't have any.
It also does not have a constraint solver and is not parametric, it feels like a big step back compared
to using the Sketcher workbench in FreeCAD.</p>
<p>If I were going to make another scale like this I would probably write a Perl script to make an SVG file instead.</p>
<p>Once I had a design I was happy with, I made the scale using a diamond drag engraver on the CNC router:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4741"><img src="https://img.incoherency.co.uk/4741/thumb"></a></p>
<p>With the engraving filled in with black paint and then sanded back.</p>
<p>And I made a tiny brass clamping piece to hold the scale on with 2x M1.6 countersunk screws:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4746"><img src="https://img.incoherency.co.uk/4746/thumb"></a></p>
<p>Why the clamping piece? Why not just countersink the holes in the scale? I made the holes in the scale slightly
oversized to allow for positioning adjustment, but if the holes were countersunk this wouldn't work.</p>
<p>The capability for repositioning the scale is my solution for when the jaws wear out: I can file the jaws flat again, and move the scale!</p>
<p><a class="img" href="https://img.incoherency.co.uk/4748"><img src="https://img.incoherency.co.uk/4748/thumb"></a></p>
<p>The writing on the scale is very small and some of the digits are distorted (in particular the "8") because of flex in my CNC router.
But it is readable.</p>
<p>I am very pleased with my Douzieme gauge, I have built it to a much higher standard than I usually manage.</p>
<p><h3>Line spacing</h3></p>
<p>If you design one of these, then you should take note that the lines on the scale should <i>not</i> strictly be spaced at equal angles,
because what you are really measuring is the <i>chord length</i> rather than the <i>arc length</i>. However
the error if you space them at equal angles is so small that you can probably ignore it. I did go to the trouble of
spacing them correctly the first time, but then realised I had messed up the alignment and couldn't be bothered doing the several-hundred
clicks in LibreCAD to rescue it, so I started again and went with equal angles. Maybe if you are better at LibreCAD than me
you could do it properly.</p>
<p><h2>Alternative designs</h2></p>
<p><h3>Vernier Douzieme gauge</h3></p>
<p>Instead of just having a <i>pointer</i> on the "moving leg", we could put a <i>Vernier scale</i> on it. That way we'd
read the scale with the same precision as a normal Vernier caliper, except the scale
is amplified by 5x compared to the object we're measuring, so we'd get 5x the measuring precision of a normal Vernier caliper.</p>
<p><h3>Micrometer Douzieme gauge</h3></p>
<p>Another idea is that instead of the legs being spring-loaded and moved by hand,
they could be moved by a screw, and we can read off the length at the legs with a micrometer
scale, which again gives us 5x the precision of the micrometer because of the leverage.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/douzieme-gauge.html</link>
   <guid>http://incoherency.co.uk/blog/stories/douzieme-gauge.html</guid>
   <pubDate>Mon, 02 Oct 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Five interesting things from the Science Museum</title>
   <description><![CDATA[I enjoyed a quick visit to the Science Museum at the weekend, and here are a few of the interesting things
I saw.]]></description>
   <content:encoded><![CDATA[<p>I enjoyed a quick visit to the Science Museum at the weekend, and here are a few of the interesting things
I saw.</p>
<p><h2>Primitive circuit boards</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/4569"><img src="https://img.incoherency.co.uk/4569/thumb"></a></p>
<p>This is obviously an exhibit showing some primitive circuit boards at various stages of manufacture, but I think the exhibit
is being updated because there was no obvious explanation posted.</p>
<p>It looks like there is a wooden pattern (out of shot to the left), which is then cast as a metal part, which then gets
machined and painted, and then turns into a working circuit board. Eh? Won't everything short out through the middle?</p>
<p>It turns out that's not how it works at all. There is an explanation on the Science Museum website, it's
a <a href="https://collection.sciencemuseumgroup.org.uk/objects/co31110">Passive component plate, type A3, for
Sargrove sprayed-circuit radio receiver</a>.</p>
<p>The "wooden pattern" is actually Bakelite, and is not a pattern at all but is the insulating substrate for the circuit.
This is then <i>sprayed</i> (how?) with metal and graphite, and then the top is machined down to remove all of the metal
except in the grooves!</p>
<p>It's kind of the opposite of a modern circuit board, where the conductive part is raised up off the substrate. In these
Sargrove circuits, the conductive part is sunk down.</p>
<p>Apparently "his idea was never taken up generally, partly because it was seen as a threat to jobs", which sounds ridiculous
now given how many modern jobs are dependent on our ability to produce cheap circuit boards.</p>
<p><h2>James Watt steam engine indicator</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/4572"><img src="https://img.incoherency.co.uk/4572/thumb"></a></p>
<p>This is a device for plotting pressure-volume diagrams from steam engines. I have done this for my
<a href="https://incoherency.co.uk/blog/tags/wigwag.html">Wig-Wag engine</a> by attaching electronic
sensors, but this device works purely mechanically.</p>
<p>The central body is a spring-loaded pneumatic cylinder, which gets plumbed into the steam engine's cylinder pressure.
There is a pencil mounted horizontally at the top of the "plunger", so as the pressure in the engine rises, the pencil rises.</p>
<p>The piece of card is attached to a piece of string, which is biased to the right by the weight, and the hook on the left
end of the piece of string is presumably attached to something on the engine which moves in proportion to the stroke.</p>
<p>Now as the engine completes a cycle, the card moves left and right, and the pencil moves up and down, and plots a representation
of how the pressure in the engine changes throughout the cycle. Ingenious.</p>
<p>As a bonus, just at the edge of the shot you can see the <a href="https://collection.sciencemuseumgroup.org.uk/objects/co59281/watts-end-measuring-machine-micrometer">Watt micrometer</a>. There is
an interesting <a href="https://www.youtube.com/watch?v=1K_NQlmOwqM">Machine Thinking video</a> on this device.</p>
<p><h2>Electric governor</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/4571"><img src="https://img.incoherency.co.uk/4571/thumb"></a></p>
<p>It was quite hard to take a photograph of this, but maybe you can see what I'm getting at.</p>
<p>This is a steam-turbine-powered electricity generator. The output voltage is applied across a solenoid
which pulls a metal rod (right of pic, vertical), and the rod is connected to a long lever which actuates a steam "throttle" (left of pic),
to create a feedback loop which keeps the output voltage constant.</p>
<p>This is a nice alternative to the <a href="https://en.wikipedia.org/wiki/Centrifugal_governor">centrifugal governor</a>, and it
directly controls the output voltage, which is what you care about, rather than the engine speed.</p>
<p><h2>Rotating oiler</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/4570"><img src="https://img.incoherency.co.uk/4570/thumb"></a></p>
<p>Two oil cups are mounted on the railing around the outside of the engine, with a brass pipe poking into an "eye". The eye
is on the end of a long hollow arm attached to the crank pin.
Oil that drips into the eye can run down the inside of the arm, into some (presumed) oil ways in the crank pin, and lubricate the crank bearing.
The arm keeps the eye on the centre line of the crankshaft even though the crank pin moves around in a circle.</p>
<p>It looks like this is actually not used, because both of the oil cups on the railing are empty, and there is a third oil cup installed
directly on the con rod, but it's a nice idea anyway. I guess it is prone to leaking because the arm spends 50% of its time upside down.</p>
<p><h2>Gnome rotary engine</h2></p>
<p>There is an area in the "Flight" section on the top floor full of aircraft engines. This area is sadly very poorly lit which makes it hard to
see much more than "metal parts are here" unless you look closely. I think it's more meant to provide an aesthetic than be an actual exhibit.</p>
<p>But the Gnome engine is worth an exhibit in its own right. The example at the Science Museum is cut away so you can see what's inside.</p>
<p>I didn't think to take any pictures, but here are some I found online:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4575"><img src="https://img.incoherency.co.uk/4575/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4576"><img src="https://img.incoherency.co.uk/4576/thumb"></a>
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/gxQ-FOhtINA" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>Instead of mounting the crank cases to the fuselage, and the propellor to the crankshaft, this engine works the other way around. The crankshaft
is fixed to the fuselage, and the propellor is attached to the crank cases. When the engine is running the entire thing spins
around with the propellor! Supposedly this helps with cooling.</p>
<p>But it's not quite as simple as that. If you turned around an ordinary engine so that the fuselage and the propellor were swapped,
you would have issues connecting the throttle cable and fuel. The Gnome engine
supplies fuel/air mixture through the inside of the crankshaft. The exhaust valves are on the top of the cylinders and are operated with
push rods. The inlet valve is in the top of the piston and is spring-loaded with no actuator. The valve simply opens when the pressure in the cylinder
is lower than the pressure in the crank case, and shuts when it's the other way around. Ingenious!</p>
<p>The Gnome engine is French and is known as a "monosoupape" (single valve) because there is only one obvious valve per cylinder.</p>
<p>I have a vague idea for a model steam engine that works a bit like this. Each cylinder would have a single port through which
the steam both enters and exits, like in an oscillator. Except instead of oscillating back and forth between an inlet port and an exhaust port,
the cylinders would be continuously rotating, fixed to the flywheel (perhaps even bored directly into the flywheel), and the port would be exposed
to steam pressure for ~half the cycle and vented to atmosphere for the other half.</p>
<p>I think one difficulty would be in sealing the port face. Oscillating engines can get away with just using a spring because the rotation is minimal.
The "rotary" version could maybe use a spring but would need a thrust bearing to allow the spring to rotate.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/science-museum.html</link>
   <guid>http://incoherency.co.uk/blog/stories/science-museum.html</guid>
   <pubDate>Wed, 23 Aug 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Designing a Bangle.js commute timer</title>
   <description><![CDATA[I work in an office occasionally, and there is a particular point on my commute where I always check the clock so I can tell
how I'm doing for time. If it's 8.30 I'm likely to be on time, before 8.30 I'm doing well, after that I might be late.
But why stop at checking my delta time at a single waypoint? Why not store a GPS trace of a reference commute and continuously
compute the delta time, like you get in time trial mode in racing games?]]></description>
   <content:encoded><![CDATA[<p>I work in an office occasionally, and there is a particular point on my commute where I always check the clock so I can tell
how I'm doing for time. If it's 8.30 I'm likely to be on time, before 8.30 I'm doing well, after that I might be late.
But why stop at checking my delta time at a single waypoint? Why not store a GPS trace of a reference commute and continuously
compute the delta time, like you get in time trial mode in racing games?</p>
<p>I want to make a Bangle.js <i>commute timer</i>, as kind of a complement to <a href="https://incoherency.co.uk/blog/stories/waypointer-moto.html">Waypointer Moto</a>:
instead of telling me where to go, it will tell me how long it's going to take. It will help me answer questions like "how many minutes
did that horsebox <i>really</i> cost me?", and "is the traffic <i>really</i> worse today or am I just more grumpy?".</p>
<p>I don't just want a rough minute-precision ETA like you get on Google Maps. When I'm stuck at traffic lights I want to see my delta time ticking up by 1 second
per second. I want to really <i>feel</i> that delay.</p>
<p>This will be very much a <a href="https://www.robinsloan.com/notes/home-cooked-app/">home-cooked app</a>.
It only needs to solve my problem, it doesn't need to be useful for anyone else. I might even hardcode the route endpoints.</p>
<p>It's easy to say "make it store a reference route and show your delta time and ETA, and update the reference route if you beat the time",
but there are a few subtleties to the implementation that make it harder than it sounds.
The purpose of this post is to come up with a design that addresses all of the subtleties, so that
I can write it right on the first try.</p>
<p><h2>Problems</h2></p>
<p>Sometimes the Bangle.js won't have picked up a GPS fix until after I have set off.</p>
<p>Sometimes it will have a GPS fix before I set off.</p>
<p>Sometimes roads are closed, or I need fuel, or the GPS stops working temporarily, or I deviate from the route for some other reason.</p>
<p>Sometimes I will loop back on myself, or the GPS signal will be noisy.</p>
<p>Sometimes I'm going home instead of to work.</p>
<p>Sometimes I will be standing still or moving very slowly.</p>
<p>When the new route is faster than the reference route and we update the reference route, the start and end points should stay fixed even if the GPS trace has
a small amount of drift.</p>
<p>Sometimes the time on the Bangle.js drifts, particularly when the battery is low.</p>
<p><h2>Solutions</h2></p>
<p>The GPS route will be a series of waypoints annotated with timestamps. This could be stored in <a href="https://en.wikipedia.org/wiki/GPS_Exchange_Format">GPX</a> format, but wouldn't have to be.</p>
<p>If the commute is about an hour long and we want under 1000 waypoints, then we want to take waypoints less frequently than once every 3.6 seconds.
Maybe a 5 second interval would be fine. Why 1000? Just an arbitrary starting point. Note that the Bangle.js does not have an awful lot of RAM and ideally
we'd keep the entire route in memory.</p>
<p>Whenever we get a fresh location, we'll look for a "target" waypoint, which we define to be the <i>nearest</i> waypoint which we are getting <i>closer to</i>. (Finding this could be <b><i>O(1)</i></b> in the common case, where you have moved a bit closer to the same waypoint you were closest to last time, but <b><i>O(n)</i></b> in the worst case, if you have to scan all waypoints).</p>
<p>If the target waypoint is the first waypoint of the route and we're more than, say, 20 metres away, then we'll say that we haven't started the route yet.</p>
<p>Otherwise, once we have the target waypoint, we can look at our current speed and our distance from the target to work out how long it will take us to get there.
We then know a point on the reference route, and the time that we expect to get there, so we can work out how long it would take us to complete the route
at the reference pace, and therefore what time we should arrive at the destination. (And if we have so far averaged 1% slower than reference pace then we can also assume that we'll continue to average 1% slower and adjust the ETA accordingly.)</p>
<p>I think the only time this target waypoint selection falls down is if we're moving very slowly, and the noise in the GPS data could cause it to think we've
moved away from the target, which means it would select a new target in the opposite direction. Maybe we say that if we're moving less than, say, 5mph,
then the target selection works differently (e.g. bias it towards retaining the existing target even if it looks like we moved away from it).</p>
<p>There's also the issue that if we're not moving, then the time to the target waypoint is infinite, so we expect never to arrive at the destination. This is
obviously wrong, so maybe we cap the "time to next waypoint" at the total time it took to reach that waypoint in the reference route.</p>
<p>So this waypoint selection method allows us to "wake up" partway through the route and still select an appropriate target. It allows us to take a diversion
for a road closure and rejoin the route with an appropriate target as we approach it. If we make sure that the "start" location for the route is 100 metres
or so up the road from my house, then it also won't accidentally start the timer while I'm still faffing about on the drive.</p>
<p>But how do we calculate the starting time for a journey where we woke up a few miles into the route? I propose that if we "start" the route with some
target other than the starting point, then we blindly import all of the preceding waypoints into the "current" route, but adjusted
to match today's timestamps. That way we end up with a complete route that we can use as the new reference if required,
and we have an estimate of the full journey time. Another option
would be to sit on the drive until the watch has a GPS fix, but that is less appealing.</p>
<p>To prevent the start/end point from drifting (e.g. if we start the journey when we're within 10 metres of the start point, it would move back by up to 10 metres every time a new reference is taken), we can maintain the original coordinates for the first and last waypoint, and adjust the time to match our best
guess at when we passed that exact point on the new journey.</p>
<p>When the GPS data is noisy we might find that the delta time and ETA become noisy. We could update them using an exponential moving average instead of
replacing them each time there is new data. Will have to experiment with that.</p>
<p>And to solve the issue where we're going in the reverse direction, we can keep separate reference routes for each direction. It might be good enough to decide which one to use based on time of day
(i.e. before noon we're going to work and after noon we're going home). Alternatively we could keep track of the delta time for each route and say
that we're travelling the route whose delta time looks most stable. I think just looking at time of day is adequate and simpler.</p>
<p>To keep the Bangle.js time in sync I will make it update the time from the GPS fix whenever there is one.</p>
<p><h2>Display</h2></p>
<p>The key pieces of information I want to display are:</p>
<p><ol>
<li>GPS status (high-quality fix, low-quality fix, or no fix at all)</li>
<li>ETA as a time of day, maybe with sub-second precision (e.g."08:57:43.1")</li>
<li>delta time to personal best, definitely with sub-second precision (e.g. "-1.5")</li>
</ol></p>
<p>After that, there is lots of other stuff that we could easily calculate: elapsed time so far, estimated time remaining, estimated total time, average speed, average speed delta, start time, current time of day, progress percentage in terms of time, progress percentage in terms of distance, probably lots more.</p>
<p>I might experiment with showing some of that, but the ETA and the delta time are the most interesting to me.</p>
<p>Once we arrive at the destination, we can switch to a different mode that shows the overall delta time and the true time of arrival. If the overall
delta time is negative (i.e. we beat the best time), then it should probably update the reference route to use the new journey.</p>
<p>But maybe we would want
that to be optional, for example if the journey was fast for some non-repeatable reason that we don't want to confound the data on future journeys?
And for that matter, maybe we'd want the option to replace the reference route even if the new journey was <i>not</i> an improvement? Not sure.</p>
<p><h2>Conclusion</h2></p>
<p>I'm not sure whether writing all this up has made things clearer in my mind or less clear. And I still don't know what to do about the case where
the reference route has loops in it. Maybe it's fine to ignore as an unlikely edge case? Maybe before storing a reference route we need to post-process it to cut out loops? Maybe it's as simple as
deleting any waypoint whose successor under the "target selection" logic has an earlier timestamp?
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/banglejs-commute-timer.html</link>
   <guid>http://incoherency.co.uk/blog/stories/banglejs-commute-timer.html</guid>
   <pubDate>Wed, 16 Aug 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The Egyptian coin box</title>
   <description><![CDATA[I have invented a new magic trick. It involves a very thin wooden box with 5 locations for coins inside, each
labelled with one of the 5 bodily senses.
A spectator places a coin inside, without telling the magician where it is. The magician
then makes a show of listening to the box, sniffing the box, etc., and successfully determines where the coin was
placed.]]></description>
   <content:encoded><![CDATA[<p>I have invented a new magic trick. It involves a very thin wooden box with 5 locations for coins inside, each
labelled with one of the 5 bodily senses.
A spectator places a coin inside, without telling the magician where it is. The magician
then makes a show of listening to the box, sniffing the box, etc., and successfully determines where the coin was
placed.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4463"><img src="https://img.incoherency.co.uk/4463/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4464"><img src="https://img.incoherency.co.uk/4464/thumb"></a></p>
<p>It has electronics hidden inside the wood which can detect the coins and then transmit the
readings over Bluetooth, which are then picked up by my Bangle.js smartwatch, which vibrates to indicate the location of the coin.</p>
<p>It uses what I believe to be 2 novel innovations in magic:</p>
<p><ul>
<li>a method for detecting coins through solid wood that can be packaged extremely thinly</li>
<li>a method for making sheets of plywood with electronics hidden inside</li>
</ul></p>
<p><h2>Presentation</h2></p>
<p>The box is fully examinable by the audience. For them to prove that it is not made out of ordinary plywood they
would need to either take the hinges off, or somehow X-Ray it. It is otherwise indistinguishable from
ordinary plywood. I <i>thought</i> that this would make it an extremely powerful trick.</p>
<p>However it might be more of a "magician fooler" than a genuinely good trick, because a lay audience just needs to think
"the box is rigged" to think they've figured out how it works. Sadly we'll never know how
good it actually is as a trick, because I don't know any actual magicians who might be able to perform it. I
have performed it myself for friends a handful of times but it did not get the kind of reaction I was hoping for. I
don't know how much of that is because it is obvious that the box is rigged, and how much is due to my poor presentation.</p>
<p>I have been reading <a href="https://www.thejerx.com/">The Jerx</a> magic blog lately. It has a lot of really good
information about performing magic in a social setting. The key idea is that instead of doing overt magic "performances",
you want to be secretly setting up magical moments that you act like you <i>weren't</i> responsible for.
That way you avoid creating a division between the audience and the performer, and
it fits more naturally in ordinary social situations. It works much better than having everyone pause the party to watch
you stumble through your unnecessarily-long lecture on Egyptian faith healing. Or so I imagine.</p>
<p><h2>Detecting coins</h2></p>
<p>The most interesting part of the trick is how it detects the coins. There is a copper plate underneath each coin
location, and another copper plate above. These plates form a capacitor, but the gap is quite large and the capacitance
is extremely low. When a coin is placed in between the plates, it acts as if the plates have been brought closer together,
and the capacitance increases. By measuring how long it takes to charge up the capacitor, you can tell how much capacitance
there is, and therefore whether or not there is a coin in between the plates.</p>
<p>I prototyped this with a pair of 3d-printed parts. Each part holds a piece of copperclad board, and one part has a cutout for the coin.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4524"><img src="https://img.incoherency.co.uk/4524/thumb"></a></p>
<p>It worked well enough to convince me that I could proceed.</p>
<p><h2>Making plywood with electronics hidden inside</h2></p>
<p>You can make plywood with electronics hidden inside by starting with 2 pieces of plywood that are half the thickness
you require, milling out a pocket for your electronics, gluing the electronics inside, and then gluing the two pieces
together.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4527"><img src="https://img.incoherency.co.uk/4527/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4529"><img src="https://img.incoherency.co.uk/4529/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4533"><img src="https://img.incoherency.co.uk/4533/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4465"><img src="https://img.incoherency.co.uk/4465/thumb"></a></p>
<p>You'll want to make sure that the mating faces have perpendicular grain directions. And once the two pieces have been
glued together, you'll then want to cut your piece of magic-plywood down to the actual shape you require so that the join is seamless.</p>
<p>Now you have the problem that your battery is glued inside the wood and you can't access it to charge it.
I left a small gap in the wood through which I can poke a USB-C charging cable, hidden behind one of the hinges.</p>
<p>Gluing a lithium battery inside a piece of flammable material is probably a safety hazard, so I put a 1A "polyfuse" on mine.
This is a type of fuse that automatically resets after some time has passed, very handy since I wouldn't have any way
to replace a blown fuse. 1 Amp is <i>way</i> more than I actually need, a lower current rating would probably be better.</p>
<p><h2>Implementation details</h2></p>
<p><h3>Capacitor plates</h3></p>
<p>Putting the copper plate <i>underneath</i> the coin is easy, I made a circuit board with the CNC router:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4531"><img src="https://img.incoherency.co.uk/4531/thumb"></a></p>
<p>But how do we get a copper plate <i>above</i> the coin? I put a solid sheet of copper connected to a common ground plane
inside the lid of the box, and conducted it to the ground plane of the main PCB <i>through the hinges of the box</i>! The
solid sheet in the top has a wire soldered to it which is soldered to one of the hinges:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4543"><img src="https://img.incoherency.co.uk/4543/thumb"></a></p>
<p>And the PCB on the bottom has a pogo pin to connect its ground plane to the hinge:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4528"><img src="https://img.incoherency.co.uk/4528/thumb"></a></p>
<p>(Why not solder that one as well? I wanted the hinge to be removable so that I can access a pin header to disconnect
the battery).</p>
<p><h3>Circuit board</h3></p>
<p>The microcontroller I used is a Seeed Studio Xiao ESP32C3. It is a good choice because it is very small, and it has a
built-in Bluetooth radio, and a built-in lithium battery charging controller. That meant I hardly had to put
any components on the board:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4533"><img src="https://img.incoherency.co.uk/4533/thumb"></a></p>
<p>We have the microcontroller board, rectangular sticky-back Bluetooth antenna, 5x 1-Megaohm resistors for the capacitor charging circuits,
a grey bodge wire (see below), a
red wire connecting the battery charging circuit to the positive terminal of the battery, a pogo pin, a pin header to
disconnect the battery, the battery, and a polyfuse.</p>
<p><h3>Measuring capacitance</h3></p>
<p>The Arduino code I use for measuring how long it takes to charge up a capacitor is:</p>
<p><pre><code>int sensor(int n, int m, int sendpin, int recvpin) {
  int counter = 0;
  for (int i = 0; i &lt; n; i++) {
    digitalWrite(sendpin, HIGH);
    for (int j = 0; j &lt; m; j++)
      if (!digitalRead(recvpin)) counter++;
    digitalWrite(sendpin, LOW);
    for (int j = 0; j &lt; m; j++)
      if (digitalRead(recvpin)) counter++;
  }
  return counter;
}
</code></pre></p>
<p><tt>n</tt> sets the number of times we charge it up/down, to help with averaging the result. <tt>m</tt> sets the number of loop iterations
we wait for it to charge up/down, <tt>sendpin</tt> is the pin that is connected to the "positive" capacitor plate through a 1-Megaohm resistor, and <tt>recvpin</tt>
is a pin connected directly to the positive plate (the negative plate is tied to ground).</p>
<p>As the charge current slowly trickles out of the <tt>sendpin</tt> and through the Megaohm resistor,
eventually the plate will get charged up enough that the <tt>recvpin</tt> goes high. In principle we could stop
the loop as soon as the pin goes high, but in practice I found the readings to be quite noisy. Running a fixed number of iterations
and counting how many the pin is low for works better. I also found it useful to measure how long it takes for the capacitor
to <i>discharge</i>. You need to wait for it to discharge regardless, you may as well get some data from it.</p>
<p>If you use a Seeed Studio Xiao ESP32C3: don't try to use pin D9, it is internally connected to ground through a 300 kOhm resistor,
which means you can never charge the capacitor up enough for it to work. I fixed this by disconnecting that pin from D9 and ran the grey wire to connect it to D0 instead.</p>
<p><h3>Bluetooth</h3></p>
<p>For some reason I was unable to make the ESP32 and the Bangle.js reliably connect to each other over Bluetooth.
There was some speculation on the Bangle.js forum that this was caused by one of the devices being slightly out of
spec on the Bluetooth timings. I don't know what the problem is. But since I only needed one-way communication, I
had an ingenious solution.</p>
<p>Instead of connecting the watch to the ESP32 to receive sensor readings, I made the ESP32 write the sensor readings
into the "manufacturer data" field of its Bluetooth advertisements! The watch can then read the values out of this field
without ever having to actually "connect" to the ESP32.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/egyptian-coin-box.html</link>
   <guid>http://incoherency.co.uk/blog/stories/egyptian-coin-box.html</guid>
   <pubDate>Sat, 05 Aug 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>dnstweak: quick local DNS spoofing tool</title>
   <description><![CDATA[I spent most of today writing dnstweak, a program that temporarily inserts
itself as the local DNS resolver (by writing to /etc/resolv.conf) and spoofs responses to
selected DNS requests.]]></description>
   <content:encoded><![CDATA[<p>I spent most of today writing <a href="https://github.com/jes/dnstweak">dnstweak</a>, a program that temporarily inserts
itself as the local DNS resolver (by writing to <tt>/etc/resolv.conf</tt>) and spoofs responses to
selected DNS requests.</p>
<p>I wanted to give it a better name but everything I could think of was already taken by too
many other people's weird hacky DNS tools.</p>
<p><h2>Why?</h2></p>
<p>Yesterday I was trying to test how a piece of software would behave if it received multiple <tt>A</tt> records
for a given domain name, but not always in the same order. I couldn't change the DNS records for the domain in question, and setting up an alternative
to test with is a lot of faff. Wouldn't it be easier to just type something like:</p>
<p><pre><code>$ sudo dnstweak foo.example.com=127.0.0.1,1.2.3.4</code></pre></p>
<p>And have it do what I want?</p>
<p>Well I didn't know of a tool to do that so I made one myself.</p>
<p><h2>How?</h2></p>
<p>It's written in go and has only one (immediate) dependency: Miek Gieben's <a href="https://github.com/miekg/dns">dns</a> library.
The <tt>dns</tt> library made it very easy to write this program.</p>
<p>At startup it grabs the first <tt>nameserver</tt> line from <tt>/etc/resolv.conf</tt> (to use as the upstream
resolver), and all <tt>search</tt> lines, stores the existing <tt>resolv.conf</tt> in memory, and writes
a new <tt>resolv.conf</tt> that persists the <tt>search</tt> lines, and points <tt>nameserver</tt> at itself.
When it exits, it restores the <tt>resolv.conf</tt> that it has stored in memory.</p>
<p>When a spoofed response has more than one IP address, they are shuffled. (Just because this is the behaviour I
wanted to test - but it would be easy to make this configurable).</p>
<p>One cool feature is that it looks up the client addresses under <tt>/proc</tt> to work out which process
each request originates from. I didn't actually need this feature but it was fun, and easy enough to do. You
need to look in <tt>/proc/net/udp</tt> to find the inode corresponding to the client's address, and then look
through all of the <tt>/proc/$pid/fd/*</tt> to find one that has the same inode, then you have found the PID
of the client, and you can look in <tt>/proc/$pid/cmdline</tt> to find out the name of the process.</p>
<p><h2>Why not?</h2></p>
<p>The most fragile part is that if it crashes then it won't restore your original <tt>resolv.conf</tt>. I recommend
taking a backup of your <tt>resolv.conf</tt> before you start. Probably <tt>dnstweak</tt> should make
such a backup itself, but would need to be careful to make sure a second run of <tt>dnstweak</tt> doesn't
overwrite the first (good) backup with a copy of the <tt>resolv.conf</tt> that the previous run created!</p>
<p>Also, maybe it should detect when systemd is managing the nameserver and try to cooperate with systemd instead of
unilaterally trampling over <tt>resolv.conf</tt>. And maybe it should watch <tt>/etc/resolv.conf</tt> with
<tt>inotify</tt> so that it can at least warn you if something else changes it back.</p>
<p><h2>Example session</h2></p>
<p>Open 2 terminal windows. We'll run <tt>dnstweak</tt> in the first and <tt>ping</tt> in the second.</p>
<p>First terminal:</p>
<p><pre><code>$ sudo ./dnstweak example.com=127.0.0.1
2023/07/11 20:41:35 dnstweak starts
2023/07/11 20:41:35 listening on 127.0.0.1:53
2023/07/11 20:41:35 using 127.0.0.53:53 as upstream resolver</code></pre></p>
<p><tt>dnstweak</tt> stays running. It has inserted itself as the local resolver by modifying <tt>/etc/resolv.conf</tt>.</p>
<p>If you run <tt>dnstweak</tt> as a non-root user, it will still work as a DNS server, but it won't be able to listen on port 53 or insert itself into <tt>/etc/resolv.conf</tt>.</p>
<p>In the other terminal, start a <tt>ping</tt> to <tt>example.com</tt>:</p>
<p><pre><code>$ ping example.com</code></pre></p>
<p>Now we get some log output from <tt>dnstweak</tt> in our first terminal:</p>
<p><pre><code>2023/07/11 20:41:37 127.0.0.1:48439 (ping/9975): A example.com: 127.0.0.1 (overridden)</code></pre></p>
<p>A request came from <tt>127.0.0.1:48439</tt>, which is a process called <tt>ping</tt> with PID 9975. It was an <tt>A</tt> lookup for <tt>example.com</tt>, and we returned <tt>127.0.0.1</tt>. Back in the other terminal:</p>
<p><pre><code>PING example.com (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.020 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.037 ms</code></pre></p>
<p>Great success.</p>
<p><h2>More</h2></p>
<p>There is more information, and Linux x86-64 binaries, in the <a href="https://github.com/jes/dnstweak">github repo</a>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/dnstweak.html</link>
   <guid>http://incoherency.co.uk/blog/stories/dnstweak.html</guid>
   <pubDate>Tue, 11 Jul 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Exploiting an insecure cipher in the wild</title>
   <description><![CDATA[I found that the topology_hiding
module for OpenSIPS encodes data using an insecure
cipher, such that it can be decoded without knowing the key, leaking both the
plaintext and the key.]]></description>
   <content:encoded><![CDATA[<p>I found that the <a href="https://opensips.org/html/docs/modules/devel/topology_hiding.html">topology_hiding</a>
module for <a href="https://www.opensips.org/">OpenSIPS</a> encodes data using an insecure
cipher, such that it can be decoded without knowing the key, leaking both the
plaintext and the key.</p>
<p><h2>Context</h2></p>
<p>OpenSIPS is an open source <a href="https://en.wikipedia.org/wiki/Session_Initiation_Protocol">SIP</a> proxy.
The topology_hiding module hides information about your network topology.</p>
<p>From the <a href="https://www.opensips.org/Documentation/Tutorials-Topology-Hiding">Topology Hiding tutorial</a>:</p>
<p><blockquote>Topology hiding is usually utilized as an approach to enhance SIP network security. Since, in regular SIP traffic, critical IP address data is forwarded to other networks, the concern is that third parties can use that information in order to direct attacks at your internal SIP network.</blockquote></p>
<p>If topology hiding is used as a security measure, then you might naively think it is a security vulnerability if it is not hiding anything.</p>
<p>However, I reported my findings to the opensips-security mailing list, and was informed that this is not a security issue.
I think I just don't know enough about SIP, but that's fine. It's still fun to exploit it.</p>
<p><h2>The encoding</h2></p>
<p>If you're using topology_hiding without the <a href="https://opensips.org/html/docs/modules/devel/dialog.html">dialog</a> module,
then the topology information is encoded into a URI parameter of the outgoing <tt>Contact</tt> header. (If you <i>are</i> using
the dialog module, then my understanding is that OpenSIPS stores the information internally and does not pass it on even in an encoded
form).</p>
<p>The 3 things that are encoded are the incoming packet's <tt>Record-route</tt> set, <tt>Contact</tt> header,
and socket address. This is done by the <a href="https://github.com/OpenSIPS/opensips/blob/a1cd6230f29fbf3a90ad55e30df36b7494ffbece/modules/topology_hiding/topo_hiding_logic.c#L1553"><tt>build_encoded_contact_suffix()</tt></a> function.</p>
<p>The information is serialised into a string, the string is encrypted, and
the result is encoded with a slight variation of base64, before being passed out as a URI parameter in the outgoing <tt>Contact</tt> header.</p>
<p>Here's an example serialisation (my example has no <tt>Record-route</tt> set)</p>
<p><pre><code>\x00 \x00                            Record-route length (0)
\x23 \x00                            Contact length (35)
sip:foo@10.0.0.5:9000;transport=udp  Contact
\x12 \x00                            Socket length (18)
udp:127.0.0.1:8000                   Socket</code></pre></p>
<p>The lengths are big-endian.</p>
<p>And here is the code that encrypts the string:</p>
<p><pre><code>for (i=0;i&lt;(int)(p-suffix_plain);i++)
    suffix_plain[i] ^= topo_hiding_ct_encode_pw.s[i%topo_hiding_ct_encode_pw.len];</code></pre></p>
<p>(<tt>suffix_plain</tt> is the string we're encrypting, <tt>p</tt> points just past the end, and <tt>topo_hiding_ct_encode_pw</tt> is the
password from the config file).</p>
<p>It XORs each byte by the corresponding byte of the password, looping the password when it is too short.
This is the <a href="https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher">Vigenere cipher</a>, but with XOR instead of addition.</p>
<p><h2>Example</h2></p>
<p>Here's an example of how you might configure the topology_hiding module in your OpenSIPS config:</p>
<p><pre><code>loadmodule "topology_hiding.so";
modparam("topology_hiding", "th_contact_encode_param", "thinfo");
modparam("topology_hiding", "th_contact_encode_passwd", "m6d90nmvg645fh");</code></pre></p>
<p>This will put the encoded data in a Contact URI parameter called "thinfo", encrypted with the password "m6d90nmvg645fh".</p>
<p>Here is an example of a <tt>Contact</tt> header that OpenSIPS could transmit:</p>
<p><pre style="white-space: pre-wrap; word-wrap: anywhere"><code>Contact: &lt;sip:jes_test_account@10.0.0.9:6000;thinfo=bTZUOUMHHUwNU0dqEg0eQjtYUw0CAwlCdARWRl0YVBcJVFtGVwYPQRQJA0UUVkIaUAIERiY1EwwdDFULB0BdWFcYBQ9TWF0G&gt;</code></pre></p>
<p><h2>Cryptanalysis</h2></p>
<p>Given that the incoming and outgoing <tt>Contact</tt> headers have the same user identifier (probably not true in every case, but
common), and given that the incoming <tt>Contact</tt> header is part of the plaintext that was encrypted, we have quite a
large fragment of known plaintext.</p>
<p>If we assume the absence of a <tt>Record-route</tt> set, then we know that this fragment starts at the 3rd byte,
and we also know that the first 2 bytes are both zero (i.e. the ciphertext equals the key for those bytes). So it is possible to simply
XOR the start of the ciphertext by the fragment that we know, and we retrieve a repeating copy of the key, which we can then use to
decode the rest of the ciphertext.</p>
<p>Even if there is a <tt>Record-route</tt> set, all is not lost! We know that our known plaintext fragment is in there <i>somewhere</i>, so we just need to
try all possible key lengths and locations of the fragment until we find one that does not present a contradiction. This runs in milliseconds.</p>
<p>I have written a <a href="https://gist.github.com/jes/9628554e9e676dbaf63e24755c9cf4cb">proof of concept</a>.</p>
<p><pre style="white-space: pre-wrap; word-wrap: anywhere"><code>$ time ./th-decode.pl
key="m6d90nmvg645fh" msg="\x00\x000\x00sip:jes_test_account@10.0.0.9:6000;transport=tcp\x12\x00udp:127.0.0.1:5000"
 
real	0m0.015s
user	0m0.011s
sys	0m0.004s</code></pre></p>
<p>Even if we didn't have a long known plaintext fragment, there is plenty of scope for an attack. You at least know the <i>form</i>
of the plaintext (e.g. you know the lengths have to add up, you know what a socket address looks like, you know that a <tt>Contact</tt> header
begins "sip:" and has an "@" sign in it).</p>
<p>Even if the key is longer than the message, we just move into the realm of <a href="https://incoherency.co.uk/blog/stories/otp-key-reuse.html">key reuse
with a one-time pad</a>, which is still no bueno. If you can collect two ciphertexts and XOR them together then you
are left with the XOR of the two corresponding plaintexts, at which point you don't care about the key at all.</p>
<p><h2>Mitigation</h2></p>
<p>Since I learnt from the opensips-security mailing list that this is not a security issue, no mitigation is necessary.</p>
<p>That said, if you <i>were</i> inclined to mitigate the problem, the best solution is probably to switch to using
the dialog module so that your topology information is kept inside OpenSIPS.</p>
<p>Also, while I have your attention, <a href="https://github.com/OpenSIPS/opensips/pull/3078">OpenSIPS does not verify hostnames in SSL certificates</a>.
I wrote a fix but it's a bit clunky, and nobody who knows better seems to care to fix it, so it's probably not going to get fixed any time soon.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/opensips-topology-hiding-encoding.html</link>
   <guid>http://incoherency.co.uk/blog/stories/opensips-topology-hiding-encoding.html</guid>
   <pubDate>Thu, 06 Jul 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Incongruous technologies</title>
   <description><![CDATA[Take saws, for example. We have saws for cutting wood, saws for cutting metals, saws optimised for cutting curved shapes,
electric saws, computer-controlled saws, and so on. Saws are pretty well explored. Saws are general-purpose.
You probably won't discover a new use for saws.]]></description>
   <content:encoded><![CDATA[<p>Take saws, for example. We have saws for cutting wood, saws for cutting metals, saws optimised for cutting curved shapes,
electric saws, computer-controlled saws, and so on. Saws are pretty well explored. Saws are general-purpose.
You probably won't discover a new use for saws.</p>
<p>But then there are some technologies that just seem so incredibly far advanced compared to other things that are possible,
 but also are only applied to incredibly specific applications.</p>
<p>Watchmaking is one example. We can make these unbelievably tiny systems of springs and gears that can keep time
quite accurately, and then when you look for other things using the same sort of technology, there's just...
nothing. Really? There isn't a single application of unbelievably tiny systems of springs and gears apart from
making watches?</p>
<p>Integrated circuits are another example. For some reason we can make ICs with such precision that we're almost <i>placing individual
atoms</i>, but it can only be used to make integrated circuits? There's literally nothing else we can make with this technology?</p>
<p>Feynman wrote about "micromachines", where IIRC the idea is you make a machine that can produce slightly-smaller versions
of all of its own parts, and then repeat the process until the machine is arbitrarily-small. Obviously it's harder than that
makes it sound, because the tolerances have to go down in tandem with the overall dimensions, but I don't see why in principle
it wouldn't work.</p>
<p>I think part of the problem is that watchmaking and IC fabrication are both highly specialised fields, and people outside these
fields kind of forget, or don't know, that the techniques are possible. If someone outside watchmaking wants to design a
small mechanism, and they start imagining gears and springs in their head, the smallest reasonable-seeming scale is still maybe 10x
larger than what is typical in watchmaking. You just wouldn't assume that you can pack dozens of gears into an
object about the size of a large coin. You wouldn't even consider such a design, it is so obviously outrageous.</p>
<p>Now I don't personally have any designs in mind that can make use of watchmaking-scale gears, or IC fab-scale
whatever-sort-of-stuff-it-is-that-ICs-are-made-of, but that's exactly the point: there aren't any other
applications because people don't have any other ideas, but I think the <i>reason</i> we don't have any ideas
is because we forget that it's possible.
So I think it would be worth trying to bear in mind that these things are possible, so that we don't overlook
possible inventions that could pop into our heads.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/incongruous-technologies.html</link>
   <guid>http://incoherency.co.uk/blog/stories/incongruous-technologies.html</guid>
   <pubDate>Sun, 02 Jul 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Triangle strip encoding</title>
   <description><![CDATA[Triangle Strip Encoding is a method of encoding an arbitrary bitstream
as a strip of triangles. I made it because I wanted an abstract-looking triangle
pattern for a ring, but I wanted the triangles to mean something.]]></description>
   <content:encoded><![CDATA[<p>Triangle Strip Encoding is a method of encoding an arbitrary bitstream
as a strip of triangles. I made it because I wanted an abstract-looking triangle
pattern for a ring, but I wanted the triangles to mean something.</p>
<p>If you want to try encoding some strings, you can try my <a href="https://incoherency.co.uk/triangle-strip-encoding/">Triangle Strip Encoding</a>
tool. I did not make a decoding tool, so you'll have to do that on your own.</p>
<p>Here's the ring I made:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4455"><img src="https://img.incoherency.co.uk/4455/thumb"></a></p>
<p>And the pattern on it:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4460"><img src="https://img.incoherency.co.uk/4460/thumb"></a></p>
<p><h2>How it works</h2></p>
<p>First, turn your data into a bitstream any way you like. I simply concatenated ASCII codes.</p>
<p><pre><code>0100101001010011</code></pre></p>
<p>Now prepare a grid with uniformly-spaced vertical and horizontal lines. You need as many vertical lines
as you have bits to encode, and you need 4 horizontal lines.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4456"><img src="https://img.incoherency.co.uk/4456/thumb"></a></p>
<p>Now plot your data on the grid, using the top 2 lines for even-indexed bits and the bottom 2 lines
for odd-indexed bits, and draw lines connecting all the points:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4457"><img src="https://img.incoherency.co.uk/4457/thumb"></a></p>
<p>Now draw lines to connect all the even-indexed points:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4458"><img src="https://img.incoherency.co.uk/4458/thumb"></a></p>
<p>And finally draw lines to connect the odd-indexed points:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4459"><img src="https://img.incoherency.co.uk/4459/thumb"></a></p>
<p>Lose the grid and you have your abstract-looking triangle pattern:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4460"><img src="https://img.incoherency.co.uk/4460/thumb"></a></p>
<p><h2>Ambiguity</h2></p>
<p>My ring encodes <tt>0100101001010011</tt> which is ASCII for "JS".</p>
<p>But a ring has no natural "up" orientation, so there are actually 2 possible ways to decode it.
One way gets you the "JS", and the other gets <tt>0x35 0xad</tt>, which is a digit "5" followed by a non-ASCII-code.</p>
<p>In general, if you get it the wrong way up, then your bitstream is reversed and inverted. It might
be fun to find English words that give other valid
English words when you reverse and invert their bits.</p>
<p><h2>Further expansion</h2></p>
<p>You can encode your data in some base other than binary, and use more horizontal lines.
For base-n, you need <b><i>2n</i></b> horizontal lines. (It would actually be possible
to use a different base to encode the even numbers vs the odd numbers, see my post on
<a href="https://incoherency.co.uk/blog/stories/chess-steg.html">chess steganography</a> for
an example).</p>
<p>Using a larger base might give
you more interesting-looking triangles, and it would definitely give you shorter sequences,
at the cost of making the decoding harder to eyeball in the absence of the grid.</p>
<p>Also, you don't need to put the values in any particular order, and the order of the values
for the top line and bottom line do not need to match. For example:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4461"><img src="https://img.incoherency.co.uk/4461/thumb"></a></p>
<p>Finally, you could run several different strips horizontally, and then connect the triangles
between them, to make a triangle <i>mesh</i> that encodes your data:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4462"><img src="https://img.incoherency.co.uk/4462/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/triangle-strip-encoding.html</link>
   <guid>http://incoherency.co.uk/blog/stories/triangle-strip-encoding.html</guid>
   <pubDate>Thu, 22 Jun 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Did I receive fraudulent DMCA takedowns?</title>
   <description><![CDATA[I received 3 DMCA takedown emails today, covering 7350 URLs on my hardbin.com IPFS
gateway. The URLs were allegedly serving infringing copies of books.
The strange part is that of those 7350 URLs, during the time for which I have nginx logs,
none of them have ever been accessed, and of the ones that I checked, none even worked.
Does this mean the DMCA takedown notices were fraudulent?]]></description>
   <content:encoded><![CDATA[<p>I received 3 DMCA takedown emails today, covering 7350 URLs on my hardbin.com <a href="https://ipfs.tech/">IPFS</a>
gateway. The URLs were allegedly serving infringing copies of books.
The strange part is that of those 7350 URLs, during the time for which I have nginx logs,
<i>none of them have ever been accessed</i>, and of the ones that I checked, <i>none even <b>worked</b></i>.
Does this mean the DMCA takedown notices were fraudulent?</p>
<p>The notices were actually sent to abuse addresses at DigitalOcean and gandi, and I think gandi
forwarded them to me.</p>
<p>I have now taken hardbin.com down completely because dealing with this sort of thing makes it less fun to run and more like hard work, but I do still have a copy of the log files.</p>
<p>I did some bash-fu to extract the IPFS hashes from the emails and grep for them in my nginx logs,
and was surprised to find <i>not a single match</i>.</p>
<p>In case you are interested, I have posted the contents of the takedown notices in github gists:</p>
<p><ul>
<li><a href="https://gist.github.com/jes/51496baaa48610f1b59a39804fd28df9">https://gist.github.com/jes/51496baaa48610f1b59a39804fd28df9</a></li>
<li><a href="https://gist.github.com/jes/597cf1fa84067586c906ac1d8c605f20">https://gist.github.com/jes/597cf1fa84067586c906ac1d8c605f20</a></li>
<li><a href="https://gist.github.com/jes/f32147236874ef736be6190c2cce4a3d">https://gist.github.com/jes/f32147236874ef736be6190c2cce4a3d</a></li>
</ul></p>
<p><a href="https://www.grahamedgecombe.com/">Graham</a> pointed me at <a href="https://law.stackexchange.com/questions/51541/has-anyone-been-convicted-of-perjury-for-false-dmca-takedown-notices">a
Law.StackExchange thread</a> covering what happens if you send false DMCA takedown notices. The short answer is I think nobody has ever
faced criminal charges, and there have been a very tiny number of civil cases.</p>
<p>The emails are sent from "notice@ciu-online.net". There is a login form on www.ciu-online.net, but it is incredibly
generic, so it's hard to work out who is behind it:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4452"><img src="https://img.incoherency.co.uk/4452/thumb"></a></p>
<p>The name at the bottom of the emails is "Gareth Young, Internet Investigator". I did find <a href="https://documents.pub/document/gareth-young-creating-a-global-internet-anti-piracy-strategy.html">a slideshow on Creating a Global Internet Anti-Piracy Strategy</a> by a "Gareth Young - Senior Internet Investigator" who apparently worked for
<a href="https://www.cov.com/">Covington & Burling LLP</a>, although the name Gareth Young does not currently appear
in their A-Z list of "Professionals". It is certainly possible that this is nothing to do with Covington & Burling LLP, I
have nothing but that slideshow to suggest any link to that company.</p>
<p>Page 14 of the slideshow, "What Are Your Options?" includes "Make it less fun to run and more like hard work".</p>
<p><a class="img" href="https://img.incoherency.co.uk/4453"><img src="https://img.incoherency.co.uk/4453/thumb"></a></p>
<p>Certainly the receipt
of these DMCA takedown notices has made hardbin.com less fun to run and more like hard work, albeit that nobody
was using hardbin.com to pirate any of the books he listed (so it has had no effect on piracy whatsoever), nor indeed
did he even <i>check</i> whether hardbin.com <i>could</i> be used to access the URLs he listed, because there were no
requests in my logs for any of the 7350 URLs. I checked a few, and they didn't work,
they just gave 504 Gateway Timeout responses.</p>
<p>Apparently the DMCA requires "a statement that the information in the notification is accurate". So what does the information in the notification
actually say?</p>
<p><blockquote>3. Statement of authority:<br><br>
I swear, under penalty of perjury, that the information in the notification is accurate [...]</blockquote></p>
<p>(The only part that the DMCA states is under penalty of perjury is the assertion that the complaining party
is authorised to act on behalf of the copyright owner. As far as I can tell, there is <i>not</i> in fact a penalty of perjury for
putting other false information in a DMCA takedown notice. But never mind that part.)</p>
<p>Gareth Young, Internet Investigator, <i>swears, under penalty of perjury, that the information in the notification is accurate</i>. But
section 2 begins:</p>
<p><blockquote>2. Copyright infringing material or activity found at the following location(s):</blockquote></p>
<p>Copyright infringing material or activity <i>could not have been found</i> at
those locations because in order to <i>find</i> it you must have <i>accessed</i> it, and since my logs show that nobody accessed it,
we can infer that Gareth Young, Internet Investigator,
<i>can not have found it</i>. It is not enough to make the leap from "this content exists at this IPFS hash"
to "this IPFS gateway allows access to this content" because you don't know if the hash is already blocked in the web server configuration,
or if the server is broken in some way that prevents access to that hash, etc.</p>
<p>I believe this amounts to <i>inaccurate information</i> in the DMCA notice.</p>
<p>I found an <a href="https://github.com/notslang/ipfs-gateway-dmca-requests">ipfs-gateway-dmca-requests</a> github
repo which documents a similar phenomenon on a different IPFS gateway, although it seems they've been subject to it
since at least the 15th of February 2022 - over a year ago.</p>
<p>The README in that repo also suggests that that person's DMCA requests also usually come from someone called Gareth Young, and
are also sent without first checking whether the allegedly infringing URLs are actually infringing.</p>
<p>So are these DMCA takedowns fraudulent? And, if so, what can we do about it?
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/hardbin-fake-takedowns.html</link>
   <guid>http://incoherency.co.uk/blog/stories/hardbin-fake-takedowns.html</guid>
   <pubDate>Wed, 21 Jun 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Book Review: Bloodhounds (includes spoilers)</title>
   <description><![CDATA[Bloodhounds by Peter
Lovesey is a locked room murder mystery. It has reasonably good reviews, and is set in Bath in the 90s, which is why
I read it. I enjoyed most of the book, and I liked that I knew most of the places the book talks about. However, the plot has a fatal flaw,
which is what has prompted me to write this post. Major spoilers lie ahead.]]></description>
   <content:encoded><![CDATA[<p><a href="https://www.goodreads.com/book/show/364840.Bloodhounds">Bloodhounds</a> by <a href="https://en.wikipedia.org/wiki/Peter_Lovesey">Peter
Lovesey</a> is a locked room murder mystery. It has reasonably good reviews, and is set in Bath in the 90s, which is why
I read it. I enjoyed most of the book, and I liked that I knew most of the places the book talks about. However, the plot has a fatal flaw,
which is what has prompted me to write this post. Major spoilers lie ahead.</p>
<p>Emma pointed out that an impossible crime is what I wanted and an impossible crime is what I got!</p>
<p><h2>The puzzle</h2></p>
<p>The Bloodhounds are a group that meets weekly to discuss crime fiction.
Milo Motion, a member of the group who lives on a boat, is due to read from a particular chapter of a particular book at the next meeting.
In the intervening week, a valuable stamp is stolen from the postal museum.
At the next meeting, when Milo opens the particular book, the stamp is discovered at the particular chapter,  as if it were a bookmark.
Milo goes straight to the police station to hand in the stamp, and he didn't have time to go anywhere else in between. The other members (including a man called Sid Towers) leave the meeting early.
After being interviewed for a few hours, Milo is escorted to his boat, under constant supervision from police, unlocks the boat, and finds the dead body of Sid inside!</p>
<p>The padlock on the boat is said to be very high quality (German-made, in fact), and shows no signs of damage. There were only ever 2 keys for it, Milo had constant possession of one, and the other was dropped in the river a long time ago. And lock-picking does not exist.
When Milo is in the boat, he leaves the padlock hanging outside and locks the door with a bolt from the inside, so nobody could have snuck in while he was asleep.</p>
<p><h2>The solution</h2></p>
<p>We learn that a disgruntled former member of the Bloodhounds, Gilbert Jones, still bears a grudge after being
snubbed by the group.
He discovers that his girlfriend of 6 months, Shirley-Ann Miller, enjoys crime fiction, and subtly leads
her into joining the group. He learns from her that Milo is going to read the particular chapter of the particular
book at the next meeting, and decides to steal the stamp and plant it in Milo's book to prove (to whom?) that he is smarter
than the Bloodhounds.</p>
<p>Fine so far. The stamp theft is relatively straightforward: he climbs up a ladder posing as a window-cleaner, breaks in through a window, and takes the stamp before the museum opens.
But how does he get the stamp into Milo's book?</p>
<p>Gilbert buys a lock that looks identical to Milo's padlock. At some time while Milo is inside the boat, with his padlock hanging outside (unlocked!), Gilbert
simply switches the locks. When Milo leaves the boat, the lock he clicks closed is <i>Gilbert's</i> lock. Gilbert hides and waits for Milo to leave, then unlocks his own lock, using his own key,
and gains entry to the boat. He locates the particular book and places the stamp in the particular chapter, leaves the boat, and locks
it with <i>Milo's</i> lock, leaving no sign of any tampering.
Milo eventually returns to the boat, unlocks his own lock, and doesn't find anything wrong. Eventually he takes the book to the Bloodhounds
meeting, whereupon the stamp is discovered.</p>
<p>Superb! Top marks so far.</p>
<p>When Milo is at the Bloodhounds meeting, Gilbert is back at the boat to put Milo's lock back,
but he doesn't know that the discovery of the stamp will lead to the meeting ending early. Sid's curiosity compels him to investigate the boat
while Milo is at the police station. Sid finds the boat unlocked,
and Gilbert is inside. Gilbert panics and hits Sid over the head with a windlass, accidentally killing him. Gilbert locks the boat with Milo's lock
and runs away.</p>
<p>What?!</p>
<p><h2>The flaws</h2></p>
<p>Gilbert can't have been at the boat to return the lock while Milo was at the Bloodhounds meeting.
In order for Milo to have collected the book with the stamp, Milo must have gained access to the boat after Gilbert had been inside the boat.
For Milo to have gained access to the boat, the boat must have been locked with Milo's lock, which means Gilbert's work was done. Gilbert
has no further need to return to the boat once Milo's lock is back on, and if Milo's lock is <i>not</i> back on, Milo can't get inside to
retrieve the book.</p>
<p>So that's the first, and most important, problem. Gilbert would not have had any reason to be anywhere near the boat during the time of the Bloodhounds meeting.</p>
<p>The other problem is that <i>even if</i> Gilbert was there to put the lock back on, why was he still there 3 hours after Milo left for the meeting?
It would take all of 30 seconds to switch the locks. And why was he inside the boat? You don't need to go inside the boat to switch the locks. It
all makes no sense.</p>
<p>There is a murder of another Bloodhounds member (Rupert Darby) later on in the story. Gilbert tries to make it look like Rupert hanged himself
out of guilt over killing Sid.
If Gilbert hadn't returned to the boat during the Bloodhounds meeting (which he patently
did not need to do), then he wouldn't have killed Sid in the first place, so there would have been no need to kill Rupert either. The entire
plot hinges around Gilbert being surprised by Sid inside the boat, even though Gilbert had no reason to be there, no reason to be there for so long,
and no reason to be inside.</p>
<p>Gilbert plants the second padlock in Rupert's jacket, so that when the police discover it they will assume
it was Rupert that did the padlock trick to gain access to the boat. But when interviewed by police later, Gilbert implies that he does not
think the police know how the stamp was planted in the book. If you don't think the police can figure out the padlock trick, what good does
it do to plant the padlock on Rupert?</p>
<p><h2>A solution to the main flaw</h2></p>
<p>The story desperately hinges on Gilbert and Sid meeting inside the boat while Milo is being interviewed by police. We either need Gilbert
to be returning the padlock during this time (which is the solution the book gives, but which is impossible, else Milo wouldn't have been able to retrieve his book), or we need Gilbert to do the padlock trick <i>a second time</i>.</p>
<p>Maybe Gilbert wants more revenge than simply planting the stamp in the book. Maybe he has another prank in mind, but this one will take a few
hours to set up, so he schedules it for when he knows Milo will be at the Bloodhounds meeting. That it takes several hours to carry out
explains why Sid catches him in the act. And whatever he does
probably either needs to be undetectable, or he needs to undo it before leaving the boat, or it needs to be embarrassing for Milo in some way, to
explain why the police never hear about whatever he did.</p>
<p>Or maybe Gilbert is <i>waiting</i> at the boat for Milo to return, so he can say "Haha! Surprise! It was me who planted the stamp in your
book and I bet you don't know how I keep getting in to your boat either!" and bask in the glory of having deceived the Bloodhounds
who previously belittled him.</p>
<p>With some sort of change along those lines, the rest of the story would make sense.</p>
<p><h2>Conclusion</h2></p>
<p>As written, the plot is totally impossible. Gilbert would have no reason to be at the boat at the time Sid was investigating, because Gilbert
<i>must</i> have switched the locks back prior to Milo collecting the book and going to the Bloodhounds meeting.</p>
<p>But <i>apart from the fact that the plot is impossible</i>, I found it an enjoyable book. I like that it is set in Bath. I like that it is set in the 90s.
I consider this to be "present day" and "relatable", compared to the typical 1930s locked room in a giant country mansion. I really liked
the padlock trick, because it's such an elegant way of gaining access to a seemingly-locked boat.</p>
<p>I plan to read more impossible crime fiction. Hopefully the next one I read will be logically consistent.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/bloodhounds.html</link>
   <guid>http://incoherency.co.uk/blog/stories/bloodhounds.html</guid>
   <pubDate>Wed, 31 May 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Taxonomy of locked room murders</title>
   <description><![CDATA[In fiction, a locked room murder is a murder where
the body is discovered in a place from which it would seem impossible for the murderer to have escaped
undetected. For example, in a room that is locked from the inside, or a room that was watched
by a security guard the entire time, or a room where the only exits were covered by CCTV. (We could
imagine an accompanying taxonomy of locked rooms). There are really only a few ways such
a murder could have been carried out. This post contains spoilers for some Jonathan Creek episodes.]]></description>
   <content:encoded><![CDATA[<p>In fiction, a <a href="https://en.wikipedia.org/wiki/Locked-room_mystery">locked room murder</a> is a murder where
the body is discovered in a place from which it would seem impossible for the murderer to have escaped
undetected. For example, in a room that is locked from the inside, or a room that was watched
by a security guard the entire time, or a room where the only exits were covered by CCTV. (We could
imagine an accompanying <i>taxonomy of locked rooms</i>). There are really only a few ways such
a murder could have been carried out. This post contains spoilers for some Jonathan Creek episodes.</p>
<p>The enjoyment from a locked room murder is in trying to work out <i>how</i> the crime was committed,
rather than <i>who</i> did it. Generally all of the clues are revealed as the story progresses,
and we are encouraged to try to solve the problem on our own before the big reveal.</p>
<p>What follows is all the different ways I could imagine a locked room murder could be carried out.
I present the tropes very roughly in order from most to least promising, in my estimation.</p>
<p><h2>1. The room is booby-trapped</h2></p>
<p>The killer (deliberately) left a rigged object, poisoned food or drink, or a deadly animal inside the room,
or tampered with the room itself in some way, such that
the victim would be killed some time after they locked the door. (If it's not deliberate, see type 8 instead.)</p>
<p>This is my favourite type of locked room murder, and I think it has the most scope for an interesting story.</p>
<p>Examples from Creek include:</p>
<p><ul>
<li>In "Mother Redcap", people die of fright when looking out of a particular window in an inn. It turns out that there are electrified nails in the floor
and the victims are being electrocuted.</li>
<li>In "The Grinning Man", the bath tub tips its occupants into a tank of water once it has enough weight in it.</li>
<li>In "The Coonskin Cap", the stab vest is rigged to inflate to suffocate the wearer, before deflating again in time to be discovered. (This is a bit different because the booby trap is on the <i>person</i> rather than in the <i>room</i>, see also type 5 since the vest is commanded to inflate by radio control).
</ul></p>
<p><h2>2. The victim sustains an injury before locking themselves in the room, and succumbs later</h2></p>
<p>This could be from a physical attack, or they could have been poisoned prior to entering the room.</p>
<p>I think the seminal example is the 1907 French serial
<a href="https://en.wikipedia.org/wiki/The_Mystery_of_the_Yellow_Room">Le Mystère de la Chambre Jaune</a> (The Mystery of the Yellow Room),
which features in the Creek episode "The Letters of Septimus Noone". In "The Letters of Septimus Noone", The Mystery of the Yellow Room
is turned into a stage musical. In a parallel to the stage musical, one of the actresses is stabbed for real,
locks herself in her dressing room, and subsequently dies in the locked room.</p>
<p>This is a clever idea, but there just aren't all that many ways to give someone an injury that they will later
die from.</p>
<p><h2>3. The victim is still alive when discovered, is killed by the discoverer</h2></p>
<p>The discoverer kills the victim upon "discovering" them, and then declares it to be an impossible crime because
the room was locked upon their arrival.</p>
<p>The discoverer should ideally appear implausible as a murderer, or have a method that makes it appear as though the
murder took place substantially before the discovery, otherwise the possibility that they did it is quite obvious.</p>
<p><h2>4. The murderer hides inside the room and sneaks out once the coast is clear</h2></p>
<p>Something about the initial investigation of the room is not sufficiently thorough, leaving the murderer the opportunity to remain
hidden and then escape later.</p>
<p>For this to be a viable strategy, the killer must <i>know</i> that the initial investigation of the room will not discover them,
otherwise it's too risky. Maybe they know it will be someone who will be in shock at the
discovery of the body, and will immediately leave the scene to seek help.</p>
<p><h2>5. The murder was committed from outside</h2></p>
<p>The victim locks themselves in a room and the murderer kills them without entering the room, and ideally makes it look like
the murder could only have taken place from inside the room.</p>
<p>Maybe a gun is fired through a letterbox. Maybe poisonous gas is piped through an air vent.</p>
<p><h2>6. The murder took place elsewhere and the body was dumped in the room</h2></p>
<p>The room must have some method of entry that you can chuck a dead body through, but which a living person
could not use. For example, maybe the room is deep underground and the only doorway has been bricked up for years,
but for some reason there is a skylight or something directly above the room that the body could be dropped into.</p>
<p>Probably hard to make a good story out of this, because as soon as we learn about the entry method, it will
become clear that a body could have been dumped through it.</p>
<p><h2>7. The method of watching the door is defective or malicious</h2></p>
<p>The security guard falls asleep. The security guard is the murderer. The "witnesses" were in on it. The CCTV is hacked so that it loops innocuous footage
of nothing happening, instead of the real footage of the murderer coming and going.</p>
<p>If you're writing a locked room murder and you don't plan to use this trope, you would probably actually lock
the room, rather than leave this possibility open, since the murder is so obviously trivial if the "watched room" is not
watched properly. So if the room is merely <i>watched</i>, rather than <i>locked</i>,
then it's either the case that the watching is defective/malicious, or the writer explicitly wants this to appear
as a strong possibility.</p>
<p><h2>8. It's not a murder, it's an accidental death</h2></p>
<p>There is no murderer, the death just happened by accident after the victim had locked themselves in the room.</p>
<p>Maybe the victim banged their head on something, maybe they suffered a heart attack, maybe they didn't know that
some innocuous-looking object in the room was actually deadly.</p>
<p><h2>9. The room was actually locked from the outside</h2></p>
<p>The murder took place conventionally, then the murderer left the room and locked the door in
such a way that it appeared that the door had been locked from the inside.</p>
<p><h2>10. The room has a secret exit which the murderer used</h2></p>
<p>The murderer goes into the room through the normal entrance, commits the murder, locks the door,
and escapes through a secret exit which nobody else knows about. Or maybe the victim was already
in the locked room, and the murderer both entered and exited through the same secret passage.</p>
<p>Similarly to type 6, it's hard to make this into a good story, because either the reader knows about the secret passage or
they don't. If they know about the secret passage then the solution is trivial, and if they don't know
about the secret passage then they don't have a fair chance of solving it.</p>
<p><h2>11. It's not a murder, it's a suicide</h2></p>
<p>The victim locked themselves in the room and then killed themselves.</p>
<p>For this trope to be at all compelling, we probably either need to be looking to explain <i>why</i> the person
committed suicide, or it needs to appear impossible as a suicide.
Suicide is the default assumption when a dead body is found inside a locked room,
so there has to be something else, otherwise we just have "It looked like a suicide, it was a suicide, the end".</p>
<p>In the Creek episode "The Seer of the Sands", a man kills himself (albeit not in a locked room) after receiving a fax containg good news.
Why? He misread the fax because a tiny insect had landed on it which appeared to place a comma in the middle of a sentence, changing the meaning
completely.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/locked-room-murders.html</link>
   <guid>http://incoherency.co.uk/blog/stories/locked-room-murders.html</guid>
   <pubDate>Wed, 24 May 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The crank position sensor works</title>
   <description><![CDATA[I have now used the 3d-printed light gate as a crank
position sensor on the Wig-Wag, and the first impression is
that it works well.]]></description>
   <content:encoded><![CDATA[<p>I have now used the <a href="https://incoherency.co.uk/blog/stories/3dprinted-light-gate.html">3d-printed light gate</a> as a crank
position sensor on the <a href="https://incoherency.co.uk/blog/stories/wig-wag.html">Wig-Wag</a>, and the first impression is
that it works well.</p>
<p><h2>Slotted disc</h2></p>
<p>I modelled a slotted disc to intermittently block the IR light on the light gate.
The disc has 36 slots, which means the resulting signal from the light gate will have 72
edges per revolution, so we can detect crank position in 360/72 = 5&deg; increments.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4435"><img src="https://img.incoherency.co.uk/4435/thumb"></a></p>
<p>I printed the disc in PC Blend, and fitted it to the crankshaft:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4424"><img src="https://img.incoherency.co.uk/4424/thumb"></a></p>
<p>It's just held on with friction, but that's adequate.
You can see a <a href="https://www.youtube.com/watch?v=OUnmgQp37Nk">video clip</a> of the engine running
with the disc in place if you like.</p>
<p>One advantage of measuring the crank position this way is that it adds no friction to the engine. OK, maybe a
tiny bit of air resistance. But if you were to connect a standalone rotary encoder you would be
adding some friction, which could make a measurable difference to how the engine runs at
low speeds under no load (which, after all, is the usual running condition for a model steam engine).</p>
<p><h2>Datalogging</h2></p>
<p>To collect data from the sensor, I wrote the stupidest Arduino program I could think of. The (analogue!)
output of the light gate is wired straight to a digital input of the Arduino, and I'm just reading it
in a loop with <tt>digitalRead()</tt> and outputting <tt>millis()</tt> to the serial port whenever the input
changes.</p>
<p>This seems to work well enough, even without any signal conditioning. I was worried that the signal
would sometimes flutter around the threshold and some debouncing would be required, but it doesn't look like it.</p>
<p>I do want to try reading the light gate with an interrupt instead of a loop. That should improve the precision of
the timestamps, and means I get to find out about changes to the pin state even while the program is busy
doing something else (for example, writing to the serial port or reading the pressure sensor).</p>
<p>It turns out that <tt>millis()</tt> is not really precise enough. At 72 steps per revolution, at 500 rpm
we have 600 steps per second, which means there's only 1 or 2 milliseconds between steps, which doesn't give
us a lot of precision on the rpm measurement (i.e. it acts like steps are either 1 or 2 ms apart, which would imply either 417 or 833 rpm, with nothing possible in between). So I should switch to <tt>micros()</tt> instead.</p>
<p>But with a bit of post-processing we can gain some precision by looking at the time taken between multiple consecutive
steps (I made my script look at all steps within the last 20 ms). This does cause some unwanted smoothing. Using <tt>micros()</tt> would be better, I'll do that for next time.</p>
<p>I have this plot showing the engine speed over time. It is labelled with 7 obvious separate "stages". These are caused
by me manually adjusting the regulator on the air supply.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4434"><img src="https://img.incoherency.co.uk/4434/thumb"></a></p>
<p>And this is the same data again, but a scatter plot of RPM against crank position:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4432"><img src="https://img.incoherency.co.uk/4432/thumb"></a></p>
<p>Hopefully that's easy enough to understand. During each revolution of the engine, the time is logged at 72
separate points. From the post-processing mentioned above, we turn the timestamp into the RPM at each of these
points, and we know to reset the crank position to 0 every 72 points.</p>
<p>(Stage 4 is noisier because the engine speed varied more, consult the other graph; I think the engine was
rattling a bit too much at this speed).</p>
<p>This shows what I really wanted to see, which is firstly that the speed varies throughout the cycle (i.e. the engine speeds up during the power stroke and slows down during the exhaust stroke). But most importantly it shows that the light gate
is not substantially losing steps! Because the speeding up and slowing down is aligned extremely well to the 72-step cycle. This is good.</p>
<p>You can see that the peak engine speed is in roughly the same place during each stage, which means over the
course of 90 seconds it can't have gained or lost more than a small handful of steps, which means it is probably
viable as a crank position sensor.</p>
<p><h2>Index pulse</h2></p>
<p>If the sensor <i>did</i> gain or lose an important amount of steps, the solution I had in mind was to make some sort of "index pulse" that fires once per revolution, always at the same place. You could do this by putting a magnet on the flywheel and sensing it separately, or (easier) break off one of the teeth on the slotted disc and look for the longer pulse from the light gate. You'd then only get 70 steps per revolution, but one of them would be 3x as long.</p>
<p>A big advantage of having an index pulse is that it gives you <i>absolute</i> crank position. Without an index pulse,
you know how many degrees the crank has rotated since you started watching, but if you don't know what position it
was in when you started then you still don't know where it is at any other time. With an index pulse, you can turn
your relative crank position measurements into absolute crank position measurements as soon as you've seen 1
index pulse.</p>
<p>So I think I probably want to add some sort of index pulse, just so that I get more confidence in the absolute
crank position. Being able to re-synchronise once per revolution is an added bonus, although not apparently
necessary. The big benefit is not having to manually synchronise when the logging starts.</p>
<p><h2>Cylinder pressure sensor</h2></p>
<p>Before I did all the light gate stuff, 
I did also move the <a href="https://incoherency.co.uk/blog/stories/measuring-wigwag-inlet-pressure.html">pressure sensor</a> to the top of
the cylinder. So now instead of measuring the inlet pressure, I'll get the pressure inside the cylinder.</p>
<p>I did this by putting a threaded hole in the brass part that plugs the top of the cylinder. The sensor
is screwed down just far enough that the bottom of the sensor is flush with the bottom of the brass part, so I think
it is not substantially affecting the volume inside the cylinder.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4387"><img src="https://img.incoherency.co.uk/4387/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4388"><img src="https://img.incoherency.co.uk/4388/thumb"></a></p>
<p>I did take some measurements from this and compared to the simulator:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4392"><img src="https://img.incoherency.co.uk/4392/thumb"></a></p>
<p>It's not a <i>brilliant</i> match; the simulator predicts a couple of sub-peaks that just don't seem to be
present in the real data. Not sure what's going on there. Maybe the sensor (or Arduino ADC) doesn't react
fast enough to changes in pressure? Maybe my sampling rate is not high enough? Maybe the simulator is wrong? Not sure.</p>
<p>But at least the speed and peak cylinder pressure sort of line up for the same supply pressure
(which we'd expect, given the work I did on <a href="https://incoherency.co.uk/blog/stories/calibrating-oscillating-engine-losses-2.html">loss
calibration</a>).</p>
<p><h2>Next</h2></p>
<p>So I probably want to switch to using <tt>micros()</tt>, break off one tooth of the slotted disc,
try out using the light gate to trigger an interrupt pin instead of reading it in a loop,
and make it log cylinder pressure and crank
position at the same time. Then I can finally try to reproduce the simulator's pressure-volume diagrams,
which will be a really good milestone.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/crank-position-sensor.html</link>
   <guid>http://incoherency.co.uk/blog/stories/crank-position-sensor.html</guid>
   <pubDate>Sat, 06 May 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>A quick 3d-printed light gate</title>
   <description><![CDATA[I need to affix a rotary encoder to my oscillating steam engine to
measure the crank rotation, so that I can plot pressure-volume diagrams from the real engine to compare to
the simulation. Rather than buy a rotary encoder,
I decided to make a light gate and slotted disc myself. I haven't done the slotted disc yet, but it will be
a pretty trivial 3d print.]]></description>
   <content:encoded><![CDATA[<p>I need to affix a rotary encoder to my <a href="https://incoherency.co.uk/blog/stories/wig-wag.html">oscillating steam engine</a> to
measure the crank rotation, so that I can plot pressure-volume diagrams from the real engine to compare to
the <a href="https://incoherency.co.uk/blog/stories/oscillating-engine-simulator.html">simulation</a>. Rather than buy a rotary encoder,
I decided to make a light gate and slotted disc myself. I haven't done the slotted disc yet, but it will be
a pretty trivial 3d print.</p>
<p>I made the light gate using components I already had in the junk box, and it only took a few hours, most of which I spent on trying to get the wrong kind of infrared sensor to work.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4394"><img src="https://img.incoherency.co.uk/4394/thumb"></a>
<br><small>(The dark one is the photodiode, the clear one is the LED)</small></p>
<p><a class="img" href="https://img.incoherency.co.uk/4397"><img src="https://img.incoherency.co.uk/4397/thumb"></a></p>
<p>It's just an infrared LED and infrared photodiode facing each other, and a couple of resistors, on a piece of stripboard, inside a 3d-printed housing. The slotted disc will run in the gap between the LED and the photodiode so that it intermittently blocks the light path, which allows me to count the pulses to work out the angle the crank has rotated at any given time.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4395"><img src="https://img.incoherency.co.uk/4395/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4398"><img src="https://img.incoherency.co.uk/4398/thumb"></a></p>
<p>The mounting holes on the plastic housing will eventually be used to screw the sensor to a piece of material that will hold it in place near the engine.</p>
<p>There is a small amount of strain relief on the cable when the PCB is screwed down, you can see in this CAD screenshot:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4396"><img src="https://img.incoherency.co.uk/4396/thumb"></a></p>
<p>As the PCB is screwed down ("up" in the pic), it clamps the cable into the housing.</p>
<p>The IR LED is powered by 5v and has a 510 Ohm current-limiting resistor. The photodiode has 5v applied to the positive side, and the negative side is the "signal" output. The signal is pulled to ground with a 680 KOhm resistor. This signal pin goes to a digital input pin on the Arduino.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4401"><img src="https://img.incoherency.co.uk/4401/thumb"></a></p>
<p>At first I thought I was going to have to use an analogue input and manually configure a threshold value to distinguish "light" and "dark" readings, but the voltage difference between light and dark is almost the entire 0v to 5v range, so it works plenty well enough connected to a digital input.</p>
<p>Some of the schematics available online involve using the photodiode to control a transistor to provide 5v to the microcontroller, but I found this not to be necessary. Probably I am in the easy case because my LED is so close to my photodiode; if you were trying to receive instructions from a television remote control from the other side of the room you would get much less signal.
The method I ended up using is from an <a href="https://www.instructables.com/IR-Photogate/">IR Photogate</a> Instructable.</p>
<p>What <i>didn't</i> work was to use one of these "infrared receivers":</p>
<p><a class="img" href="https://img.incoherency.co.uk/4399"><img src="https://img.incoherency.co.uk/4399/thumb"></a></p>
<p>These detect infrared sources that switch on and off at 38 kHz, and the output goes low when it detects a 38 kHz signal and high
when it doesn't. I thought this would be easier than using a photodiode (even though I need to make a 38 kHz signal instead of a solid light source) as I thought the photodiode would be too analogue and annoying. The issue I found with the "infrared receiver" is that the output seems to go high again after about half a second, <i>even if the 38 kHz signal remains present</i>. I guess these things are intended to be used for brief bursts of communication, which will involve the 38 kHz signal rapidly appearing and disappearing. Using the photodiode turned out to be easier.</p>
<p>From some testing by sticking a piece of paper in the gap between the LED and the photodiode, I think this is going to work nicely.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/3dprinted-light-gate.html</link>
   <guid>http://incoherency.co.uk/blog/stories/3dprinted-light-gate.html</guid>
   <pubDate>Thu, 04 May 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Revisiting oscillating engine loss calibration</title>
   <description><![CDATA[Since my Wig-Wag has run in a bit now, I have revisited
the loss calibration.]]></description>
   <content:encoded><![CDATA[<p>Since my <a href="https://incoherency.co.uk/blog/stories/wig-wag.html">Wig-Wag</a> has run in a bit now, I have revisited
the <a href="https://incoherency.co.uk/blog/stories/calibrating-oscillating-engine-losses.html">loss calibration</a>.</p>
<p><h2>Measuring RPM</h2></p>
<p>Last time, I measured the engine speed by measuring the time between the pulses in the audio track of the video.</p>
<p>I'm now measuring it with the <a href="https://incoherency.co.uk/blog/measuring-wigwag-inlet-pressure.html">inlet pressure sensor</a>!
This is possible because the pressure drops when
the port opens, so you can look at the frequency of the resulting waveform to work out how fast the engine
is running:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4325"><img src="https://img.incoherency.co.uk/4325/thumb"></a></p>
<p>My first attempt at this was to write some stupid ad-hoc code for peak detection and then work out the engine
speed based on the time between peaks. This didn't work very well:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4372"><img src="https://img.incoherency.co.uk/4372/thumb"></a></p>
<p>I think the data was too noisy for my stupid peak detection to work properly.</p>
<p>So next I tried taking the FFT of a sliding window of pressure readings and then saying that the frequency with
the highest peak (within a sensible range) is the most likely engine speed. It sometimes picks up harmonics
though (e.g. 2x or 0.5x the true speed).</p>
<p><a class="img" href="https://img.incoherency.co.uk/4373"><img src="https://img.incoherency.co.uk/4373/thumb"></a></p>
<p>I solved this by manually adjusting the "sensible range" at different
points in the data until all the harmonics seemed to be gone.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4374"><img src="https://img.incoherency.co.uk/4374/thumb"></a></p>
<p>And finally, taking an exponential moving average of this data, we get the RPM plot that I'm treating as the "truth".</p>
<p><a class="img" href="https://img.incoherency.co.uk/4375"><img src="https://img.incoherency.co.uk/4375/thumb"></a></p>
<p>Working out RPM from the inlet pressure is good enough for this purpose, but I still want to use an encoder on the crankshaft to measure the crank position
when I come to plotting pressure-volume diagrams.</p>
<p><h2>Measuring supply pressure</h2></p>
<p>Last time, I got the supply pressure from the number shown on the gauge on the compressor. I don't have a lot
of confidence in that gauge, and now that I have the inlet pressure sensor I can use that instead. I'm saying
that the <i>supply pressure</i> at any given time is the peak pressure from the inlet pressure sensor over the
last 0.6 seconds. This is a long enough window that it covers a peak from the last cycle even at the lowest engine speeds.</p>
<p>So then we can draw a scatter plot of speed-vs-pressure from every datapoint:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4379"><img src="https://img.incoherency.co.uk/4379/thumb"></a></p>
<p>It is a bit noisy, but it does follow the form of the theoretical relationship:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4378"><img src="https://img.incoherency.co.uk/4378/thumb"></a></p>
<p><h2>Loss calibration</h2></p>
<p>Armed with a representative sample of speed and pressure datapoints, I manually
adjusted the loss torque in the simulator until the simulated engine speed matched the real engine speed for the same supply pressure (this time
also using the "reservoir" supply model I described in <a href="https://incoherency.co.uk/blog/more-inlet-pressure-measurements.html">"More inlet
pressure measurements"</a>).</p>
<p>Here's the old vs new loss calibration curve:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4380"><img src="https://img.incoherency.co.uk/4380/thumb"></a></p>
<p>(I don't know why the new line is wiggly - I'm guessing it's caused by uncertainty in where exactly the "true" curve
runs from when I picked samples from the speed-vs-pressure scatter plot).</p>
<p>Because the engine now runs more freely, it can both run slower without stalling and run faster on any given supply pressure.
So the range of recorded speeds is larger, and the friction is lower at all speeds.</p>
<p>And here's the quadratic fit from LibreOffice:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4381"><img src="https://img.incoherency.co.uk/4381/thumb"></a></p>
<p>In light of this, I've added support for a quadratic loss model to the simulator.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4382"><img src="https://img.incoherency.co.uk/4382/thumb"></a></p>
<p>I don't know if that UI is really the best way to represent it. Maybe I should make it clearer that the values
are coefficients of a quadratic function.</p>
<p>And here's the scatter plot from above (red), with the measured speed-vs-pressure curve from the simulator (green), using the quadratic loss
model:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4383"><img src="https://img.incoherency.co.uk/4383/thumb"></a></p>
<p>That's close enough for me!</p>
<p><h2>Engine modifications</h3></p>
<p>Now that the loss model in the simulator might be reasonably close to reality, I wanted to simulate some
engine modifications to see if we can find improvements on the standard Wig-Wag configuration. All
of these cases are with 200 kPa supply pressure (= ~30 psi).</p>
<p>(Note all the following are using a simulated version of <i>my actual engine</i>, which means the bore is 15.2mm,
the gap above piston at TDC is 8mm, and the piston+rod length is 61mm).</p>
<p>Firstly, if we were to drill out the cylinder port, would we be able to improve efficiency, power, or both?</p>
<p><a class="img" href="https://img.incoherency.co.uk/4384"><img src="https://img.incoherency.co.uk/4384/thumb"></a></p>
<p>The standard cylinder port is 2mm. We can improve both peak power (by about 50%!) and peak efficiency by drilling this out
to maybe 4mm. (Though note that peak power and peak efficiency are not achieved at the same speed).</p>
<p>What about if we left the cylinder port as standard and drill out the inlet/exhaust ports instead?</p>
<p><a class="img" href="https://img.incoherency.co.uk/4385"><img src="https://img.incoherency.co.uk/4385/thumb"></a></p>
<p>The standard inlet/exhaust ports are 2.5mm. We can improve both peak power and peak efficiency by drilling
these out to about 4.5mm.</p>
<p>And finally, what if we drilled all 3 (to a single size)?</p>
<p><a class="img" href="https://img.incoherency.co.uk/4386"><img src="https://img.incoherency.co.uk/4386/thumb"></a></p>
<p>Somewhere between about 3mm and 3.5mm looks best.</p>
<p>So it should be pretty easy to get about 50% more power out of a Wig-Wag at 200 kPa just by tactically drilling
out some/all of the ports. I don't want to make any modifications to my actual engine until after I have managed to
plot some pressure-volume diagrams from it, so my next move is probably to put a threaded hole in the top of the cylinder and fit
the pressure sensor to the cylinder, and make the crank position sensor.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/calibrating-oscillating-engine-losses-2.html</link>
   <guid>http://incoherency.co.uk/blog/stories/calibrating-oscillating-engine-losses-2.html</guid>
   <pubDate>Mon, 01 May 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Coriolis fountain</title>
   <description><![CDATA[I have an idea for a cool-looking water fountain. It's based on the coriolis force, which
is where an object travelling in a straight line appears to be travelling in a curved line when viewed from a rotating reference frame.]]></description>
   <content:encoded><![CDATA[<p>I have an idea for a cool-looking water fountain. It's based on the <a href="https://en.wikipedia.org/wiki/Coriolis_force">coriolis force</a>, which
is where an object travelling in a straight line appears to be travelling in a curved line when viewed from a rotating reference frame.</p>
<p><h2>Concept</h2></p>
<p>Imagine one of those lawn sprinklers that has angled nozzles that spray
jets of water as they spin around in circles:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4369"><img src="https://img.incoherency.co.uk/4369/thumb"></a></p>
<p>Now imagine the arms are made longer, and the jets are more powerful, and the angles and
motion are controlled so that the jets of water land exactly where you want them.</p>
<p>In fact, you don't have to imagine, because I made a simulation.</p>
<p><a href="https://incoherency.co.uk/coriolis-fountain/">Check out my simulation here</a></p>
<p>It's not super easy to control (the angle controls, in particular, are confusing) but you can make the jets
loop around and return to the nozzle they came from, or all cross in the middle, or do several spirals before
returning to the ground, etc.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4368"><img src="https://img.incoherency.co.uk/4368/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4367"><img src="https://img.incoherency.co.uk/4367/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4366"><img src="https://img.incoherency.co.uk/4366/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4365"><img src="https://img.incoherency.co.uk/4365/thumb"></a></p>
<p><h2>First implementation</h2></p>
<p>I don't know if I'm ever going to actually build this, but for a proof of concept
we could mount the Coriolis fountain in a small paddling pool.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4370"><img src="https://img.incoherency.co.uk/4370/thumb"></a></p>
<p>We'd put a raised platform in the centre with a large gear on it, fixed in place.
There would be a frame on top of this platform which is able to rotate around the centre.
The frame would be driven around the gear by a motor mounted on the rotating frame, something like this, from my <a href="https://incoherency.co.uk/blog/stories/pikon-telescope-hardware.html">robotic telescope mount</a>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1963"><img src="https://img.incoherency.co.uk/1963/thumb"></a></p>
<p>The speed of the motor would be radio-controlled. Obviously it needs to be waterproof.</p>
<p>The rotation axis would be hollow, and a submersible pump would go down it to be submerged in the water in the paddling pool. It doesn't
matter that the pump rotates with the frame, it still pumps. The output
of the pump splits into 3 (or however many) and runs off down the arms to the nozzles. The nozzles have 2-axis control via radio-controlled servos.</p>
<p>Then we just need to put a battery and an RC receiver on the rotating frame, and the whole thing can be controlled remotely with normal RC gear. Since both the pump
and the drive motor are located on the rotating frame, none of the cables or hoses need to pass through rotating fittings.</p>
<p>We could add per-nozzle flow rate control by having a (strong?) servo motor clamp down on the hose to limit the flow.</p>
<p><h2>More</h2></p>
<p>Once the concept is proven with manual radio control, we can look at automating the control.
In increasing order of complexity:</p>
<p><ol>
<li>the rotation speed and nozzle angles could be set manually and left alone</li>
<li>we could have a small number of preset patterns and the system cycles between them either on a timer or on command</li>
<li>we could have <i>animated</i> patterns, where the nozzle angles or rotation speed can vary over time</li>
</ol></p>
<p>Probably we'd want a microcontroller onboard the rotating frame to control the animations. And we'd either want some power cables
running to the frame through slip rings, or maybe solar panels if we can tolerate it not running when it's not sunny.</p>
<p>And it would be cool to make it a permanent installation in a big pond or something. Sadly I don't have anything suitable.
Do you have a big pond or lake?
Do you want a Coriolis fountain? Email me, let's talk. I would love to help you make a Coriolis fountain.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/coriolis-fountain.html</link>
   <guid>http://incoherency.co.uk/blog/stories/coriolis-fountain.html</guid>
   <pubDate>Sat, 29 Apr 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The KRC-2 regenerative receiver kit: a review</title>
   <description><![CDATA[I recently learnt about regenerative radio receivers. They
reintroduce some of the output of an amplifying transistor back into the input, to get more gain.
It's a step up from crystal radios, and not as complex as
superheterodynes. I bought a KRC-2
kit and this post is my review.]]></description>
   <content:encoded><![CDATA[<p>I recently learnt about <a href="https://en.wikipedia.org/wiki/Regenerative_circuit">regenerative</a> radio receivers. They
reintroduce some of the output of an amplifying transistor back into the input, to get more gain.
It's a step up from <a href="https://en.wikipedia.org/wiki/Crystal_radio">crystal radios</a>, and not as complex as
<a href="https://en.wikipedia.org/wiki/Superheterodyne_receiver">superheterodynes</a>. I bought a <a href="https://kitradio.bravesites.com/regenerative-receiver-krc-2">KRC-2</a>
kit and this post is my review.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4359"><img src="https://img.incoherency.co.uk/4359/thumb"></a></p>
<p>The short review is that I like it and if you want to build a regenerative receiver you should get it.</p>
<p>It took me about 3 hours to put the kit together. The instructions are pretty good and easy enough to follow, they come in a nice booklet.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4358"><img src="https://img.incoherency.co.uk/4358/thumb"></a></p>
<p><h2>Regeneration board</h2></p>
<p>The first job is to solder up the "regenerative board". I was surprised to find that the copper side of the PCB is isolation-routed.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4340"><img src="https://img.incoherency.co.uk/4340/thumb"></a></p>
<p>I have <a href="https://incoherency.co.uk/blog/stories/pcb-milling-2.html">had a go at this myself</a> in the past:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3218"><img src="https://img.incoherency.co.uk/3218/thumb"></a></p>
<p>And while that particular PCB did work, it is the only success I've had. Every other attempt has failed in one way or another, because I was
trying to design to the kind of tolerances I expect from JLCPCB.</p>
<p>I think the method used in the KRC-2 design is much better, because it maximises the width of the traces and the area for the solder pads.
You are much more likely to produce a successful PCB with this method than if you try to lay it out like a normal PCB.
I wonder how much trouble it is to make layouts like this in KiCad...</p>
<p>The other side seems to be screen-printed:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4341"><img src="https://img.incoherency.co.uk/4341/thumb"></a></p>
<p>The footprint for the transistor requires the "base" leg to be bent the opposite way to what you'd normally expect, which confused me for a few minutes:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4343"><img src="https://img.incoherency.co.uk/4343/thumb"></a></p>
<p>It's bent towards the flat side instead of the rounded side. This is contrary to both the usual practice and the diagram in the instructions:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4356"><img src="https://img.incoherency.co.uk/4356/thumb"></a></p>
<p>The coil seems to be wound around a piece of plastic M10 threaded rod:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4346"><img src="https://img.incoherency.co.uk/4346/thumb"></a></p>
<p>I think this is a good idea, as it gives you nice consistent spacing between the turns and means you don't need insulated wire.</p>
<p><h2>Case assembly</h2></p>
<p>With the PCB done, we move on to putting everything together in the case.</p>
<p>I was surprised to find a second PCB already fitted inside the case:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4347"><img src="https://img.incoherency.co.uk/4347/thumb"></a></p>
<p>This is the "oscillator board". Why is this ready-made? Why not let me put this one together myself?</p>
<p>Probably because the soldering is much trickier (it uses SMD resistors, and has quite a few flying parts
connected to the rotary switch) and by the looks of it the variable capacitor needs to be trimmed by hand, which presumably is quite a skilled job and can't be done until
the board is assembled. Fair enough.</p>
<p>The KRC-2 seems to be an unusual regenerative receiver, in that it uses a 10.7 MHz oscillator mixed with the incoming signal from the antenna, which I haven't
seen on any other designs. According to the documentation, this reduces spurious emissions and makes the regeneration control more stable. I don't know enough about radio to judge
the pros and cons.</p>
<p>Assembling the case involves attaching the battery holders to the back panel, the "sense" and "regen" knobs and speaker to the front panel, and wiring the battery, antenna connection,
regenerative board and oscillator board all together.</p>
<p>The speaker is glued to the back of the front panel with PVA glue around the edge of the paper cone. This would not be my first choice,
although this particular speaker doesn't appear to have any provision for mounting hardware. Maybe you could hold the back of the
speaker down with tabs against the metal? The glue seems to have stuck well enough, but I'm not sure whether it would rip the paper cone if I ever tried to take it apart.</p>
<p>The last step of the assembly is to solder wires on to the solder tabs at the top of the oscillator board. The instructions ask you to take the top panel off the case in
order to access this, but I found this to be impossible. You can see here that the top panel is glued to the batten, which is also glued to the side panel:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4350"><img src="https://img.incoherency.co.uk/4350/thumb"></a></p>
<p>I'm not even sure how this is meant to have gone together. If the top panel were removable when the screws were removed, then it would either take the batten with it or not, and in either
case there would be nothing remaining to join the side panel to the top panel. I wonder if this is a design revision that hasn't made it into the instructions?</p>
<p>Anyway, unable to remove the top panel, I came up with an alternative method of soldering the wires to the tabs, which was to use some tweezer heroics to hold the wires in place and
then reach the soldering iron all the way in to the corner:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4351"><img src="https://img.incoherency.co.uk/4351/thumb"></a></p>
<p>This worked, but after I finished I had a better idea: I think if you were to remove both the front and rear panel, you could solder the wires in place on the bench at your leisure,
and then snake one of the panels through the housing and screw them both back on from the outside.</p>
<p><h2>Trimming</h2></p>
<p>To trim the regeneration, there is a 20-turn trimpot on the regenerative board. The instructions ask you to set "sense" and "regen" to the middle, turn the trimpot
all the way down, switch to "range 1" (which I assume is the 1-10 MHz range), give it 10 seconds to warm up, and then slowly advance the trimpot until a hiss is heard in the speaker.</p>
<p>Well I heard a hiss in the speaker even with the trimpot at minimum, and it hardly changed at all even when I turned it all the way to maximum.</p>
<p>I thought that probably I had made a soldering error, but before taking it all back apart I played around with it a bit and worked out that the quiet hiss I had been hearing in the speaker
"doesn't count". The <i>real</i> hiss that you're looking for is much louder, and you're more likely to find it if you tune somewhere to the middle of the frequency range instead
of at the very bottom.</p>
<p><h2>Use</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/4359"><img src="https://img.incoherency.co.uk/4359/thumb"></a></p>
<p>Moving left to right:</p>
<p>The "regen" knob is a potentiometer on the regenerative feedback, to control the strength of the regeneration. If you set it too low you don't hear anything (beyond
the quiet hiss that is always present). Once you approach the critical point the hiss gets louder, and beyond the critical point it causes whistles and buzzes. You can
tune it just beyond the critical point if you want to listen to Morse code or single-sideband, and just below the critical point if you want to listen to AM.</p>
<p>The "sense" knob is a potentiometer on the antenna input. It is suggested that you use this knob to control the audio volume, but it seems like the receiver would benefit from
a second volume knob because attenuating the incoming signal does more than just make it quieter.</p>
<p>The next knob is labelled "fine" and is used to make fine adjustments to the frequency after having selected a frequency with the large knob.</p>
<p>The last knob is a rotary switch that selects between the 3 different frequency ranges, and is also a power switch.</p>
<p>The receiver is quite hard to tune, but that's fine, that's what makes it fun to use! If I just wanted to switch a radio on and listen to something
I would have bought a mass-produced one.</p>
<p>It seems to be sensitive to how close my hand is to the left hand side of the box, which is where the coil on the regneration board lives. In some configurations you can almost play it like a <a href="https://en.wikipedia.org/wiki/Theremin">Theremin</a>.</p>
<p>I expected to be able to tune some medium-wave stations at the bottom end of the 1-10 MHz range, but was almost entirely unsuccessful. I did manage
to find TalkSport once, but it was extremely sensitive to small movements on all of the knobs. I've had most success listening to international stations between 10 MHz and 15 MHz. I don't know how much of this is due to my antenna (I have ~5 metres of wire hanging indoors, which is about 1/4 of a wavelength at 14MHz), how much is due to the receiver, and how much is due to ionospheric conditions. Sadly the foreign stations mostly seem to speak foreign languages, so I struggle to understand what they're saying.</p>
<p>I tried grounding the receiver through the electrical earth, but it seemed to introduce a lot of interference (choppy noises). For now I've got the "ground" connection tied to a metal shelving rack, which seems to be a slight improvement over nothing at all. I intend to replace the antenna with a wire hanging in the roof ridge in the loft, with a coax running down to my office. I don't know what to do about grounding, if anything. The KRC-2 instructions include a diagram that suggests hammering a spike into the ground.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/krc-2-regenerative-receiver-review.html</link>
   <guid>http://incoherency.co.uk/blog/stories/krc-2-regenerative-receiver-review.html</guid>
   <pubDate>Tue, 25 Apr 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>More inlet pressure measurements</title>
   <description><![CDATA[I'm not completely sure what has changed, but I'm now getting more convincing-looking inlet pressure data.]]></description>
   <content:encoded><![CDATA[<p>I'm not completely sure what has changed, but I'm now getting more convincing-looking inlet pressure data.</p>
<p>This came about because I tried to reproduce the real-life observations in the simulator and did not succeed, so I repeated
the real-life measurement and this time I got a different result. (As any good scientist knows: if you don't get the results
you want, you should repeat the experiment until you do).</p>
<p>This chart shows today's measurement of inlet pressure over time, for representative samples with 4 different supply pressures:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4325"><img src="https://img.incoherency.co.uk/4325/thumb"></a></p>
<p>The "0" kPa line is from running with a 0 indicated on the regulator pressure gauge (<a href="https://www.youtube.com/watch?v=qZqKqhykAUc">video</a>),
which maybe is about 30 kPa judging by the line on the graph?</p>
<p>And the trace from before was more like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4321"><img src="https://img.incoherency.co.uk/4321/thumb"></a></p>
<p>That's with 200 kPa supply pressure.
If we draw straight lines past the sharp dips, it looks more like the new version:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4326"><img src="https://img.incoherency.co.uk/4326/thumb"></a></p>
<p>So my best guess at what has happened is that the engine previously had a leak from the port faces at some point
during the cycle, which is now fixed. Such a leak would allow air to rapidly vent to the atmosphere through the inlet port,
instead of having to pass through the cylinder.</p>
<p>In between, I had dismantled the engine, cleaned all the dirty oil off,
re-lubricated and reassembled. I don't know that that would have made a substantial difference, but I can't think
what else I changed.</p>
<p>The other obvious difference is that the peak pressure now approximately matches the indicated supply pressure instead of exceeding it.
I also don't know why this would have changed, but it could just be that the gauge on the compressor is not very accurate.</p>
<p><h2>Simulator</h2></p>
<p>I added an option to the simulator to allow the configuration of a "reservoir" which supplies the cylinder, to allow the pressure
to drop when the port opens and then slowly fill back up once it closes. You can use it if you turn off the "Supply from infinite volume?"
option.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4327"><img src="https://img.incoherency.co.uk/4327/thumb"></a></p>
<p>It basically acts like a spherical air tank of a given volume, with an orifice connected to the inlet port on one side and an orifice
connected to an infinite volume of the nominal supply pressure on the other side.</p>
<p>The reservoir configuration of a 12000 mm<sup>3</sup> volume and a 0.7mm fill port gives pressure drops roughly matching what I observed
in real life.</p>
<p>I don't yet have a convenient way to overlay the plots on the same chart, but here are traces of the reservoir pressure from the simulator for 200 kPa, 140 kPa, and 70 kPa
supply pressures, with the load manually adjusted as per the <a href="https://incoherency.co.uk/blog/stories/calibrating-oscillating-engine-losses.html">calibrated losses</a>
so that it runs at the same speed as the real-life engine did at the same pressure.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4330"><img src="https://img.incoherency.co.uk/4330/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4329"><img src="https://img.incoherency.co.uk/4329/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4328"><img src="https://img.incoherency.co.uk/4328/thumb"></a></p>
<p>The range between the maximum and minimum value is shown in the number at the left hand side. Comparing this to the real-life chart from above (shown again for your convenience):</p>
<p><a class="img" href="https://img.incoherency.co.uk/4325"><img src="https://img.incoherency.co.uk/4325/thumb"></a></p>
<p>We can see that the magnitude of the pressure drop is about the same in all cases, although the waveform is not quite the same.</p>
<p>With 200 kPa supply, the pressure drops to about 150 kPa. With 140 kPa supply it drops to about 105 kPa, and with 70 kPa supply it drops to about 55 kPa.</p>
<p>The shape of the falling edge of the reservoir pressure plot kind of mirrors the inlet port flow rate (as you'd expect):</p>
<p><a class="img" href="https://img.incoherency.co.uk/4331"><img src="https://img.incoherency.co.uk/4331/thumb"></a></p>
<p>I don't know why we don't see a shape like this in real life.</p>
<p>Possible explanations for the differing waveform include
that the hose in real life is not actually a spherical reservoir, or that the regulator is actually supplying the hose with high pressure air through a variable-sized
orifice, whereas the simulator has a fixed-size orifice supplying lower pressure.</p>
<p>But I'm happy that the magnitude of the pressure drop lines up with real life.</p>
<p><h2>Next</h2></p>
<p>I'll probably want to re-record the loss calibration data now that the engine is running better (the fact that it can now run on lower pressure suggests that losses are reduced),
and re-calculate
the calibration curve in the simulator now that I can use the "reservoir" model to simulate the pressure drop in the supply hose.</p>
<p>I also still want to try adding a small reservoir to the real-life engine, to see if it reduces the magnitude of the real-life pressure drop.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/more-inlet-pressure-measurements.html</link>
   <guid>http://incoherency.co.uk/blog/stories/more-inlet-pressure-measurements.html</guid>
   <pubDate>Tue, 18 Apr 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Measuring Wig-Wag inlet pressure fluctuations</title>
   <description><![CDATA[I have connected an electronic pressure sensor near the inlet of my Wig-Wag so that
I can test the hypothesis that the actual pressure available at the inlet changes throughout the cycle of the engine.]]></description>
   <content:encoded><![CDATA[<p>I have connected an electronic pressure sensor near the inlet of my <a href="https://incoherency.co.uk/blog/stories/wig-wag.html">Wig-Wag</a> so that
I can test the hypothesis that the actual pressure available at the inlet changes throughout the cycle of the engine.</p>
<p>The idea is that the hose restricts the flow of air. So when the engine's inlet port opens, the air at the end of the hose drains
into the cylinder, and it takes time for the hose to fill back up again.</p>
<p><h2>Pressure sensor</h2></p>
<p>My setup looks something like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4319"><img src="https://img.incoherency.co.uk/4319/thumb"></a></p>
<p>In that picture, the laptop is running the Arduino IDE's "Serial Plotter", there is an Arduino Nano on the breadboard running the "AnalogReadSerial"
example program, there is a pressure sensor connected to an analogue input of the Arduino, and screwed into an aluminium fitting that I made, and
the aluminium fitting is inline with the air supply hose.</p>
<p>This picture better shows the connection of the sensor to the air hose:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4314"><img src="https://img.incoherency.co.uk/4314/thumb"></a></p>
<p>I got the sensor from eBay for about &pound;15 (search "pressure transducer"). It takes a 5 volt supply and gives an analogue output between 0.5v and 4.5v, supposedly linear in its range of measurement. Mine
has a 30psi range (= 200 kPa), but there are others with different ranges.</p>
<p><h2>First measurements</h2></p>
<p>Here's a video of the system in use:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/N19xE4SbPck" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>You can clearly see that the measured pressure is not constant, and does indeed vary throughout the engine's cycle. The simulator does not simulate
this, it assumes that the inlet pressure is constant. The simulator acts as if the inlet port is connected to a high-pressure "second atmosphere".</p>
<p>There are a few points in the video where the plotted pressure goes up and the engine slows down: this is because I was pressing my finger against
the flywheel to add some load to the engine. It's not obvious to me whether the measured pressure increase is primarily because the engine is running more <i>slowly</i>
(so there is more time for the hose to "fill up" with air when the port is closed), or because the engine is providing more resistance (so the hose doesn't drain
as quickly when the port is open). Maybe both.</p>
<p>The pressure measurement has two obvious peaks throughout the cycle, and the smaller one gets larger as the load increases:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4317"><img src="https://img.incoherency.co.uk/4317/thumb"></a></p>
<p>From playing around, it seems like it stalls at the point where the small peak meets the large peak. Not sure if that means anything interesting.</p>
<p><h2>The long hose</h2></p>
<p>To test the hypothesis that the long hose is causing the restriction, I can remove it and connect the air gun directly to the compressor:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4315"><img src="https://img.incoherency.co.uk/4315/thumb"></a></p>
<p>If the long hose is the restriction, then when the hose is connected we'd expect the measured pressure to be lower and to fluctuate more.</p>
<p>I captured pressure data from several runs at three different pressures, both with and without the long red hose.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4320"><img src="https://img.incoherency.co.uk/4320/thumb"></a></p>
<p>The "error bars" are showing the range between the minimum and maximum recorded pressure from the sensor, over a period of 5 seconds in each case.</p>
<p>We can see that with the long hose connected, the average pressure is lower as we expected, but also <i>the magnitude of the fluctuation is lower</i>.
So I think that while the long hose does increase flow restriction overall, it also acts a bit like a second air tank, allowing <i>more</i> air
to flow for short periods without changing the pressure as much, because it can drain out of the hose without having to come through the valve on the main tank.</p>
<p>It may also be notable that the maximum recorded pressure appears to <i>exceed</i> the supply pressure in each case. I am not yet sure whether this is because of
the engine pushing air back into the hose, or just a result of mis-calibration of either the electronic sensor or the gauge on the compressor.</p>
<p><h2>Conclusion</h2></p>
<p>For a more accurate simulation: instead of exposing the inlet port directly to the "second atmosphere", the inlet port could be exposed to a reservoir
(representing the hose)
that is itself connected to the second atmosphere through a small orifice. We'd then use the selected air flow method to calculate both the flow from
the reservoir to the port, <i>and</i> the flow from the supply pressure into the reservoir. I'd also like to add an "oscilloscope" to the simulator so
that you can get it to plot things like the pressure in the reservoir over time, to see how it compares to the real-life data.</p>
<p>For a better-running engine: maybe add a large air reservoir near the inlet port? It should
make the engine run faster on any given supply pressure because the pressure won't drop as far when the port is open. It might be interesting to try this with
a valve on the entrance to the reservoir, so that it can be "turned off" while the engine is running, to more clearly see what effect it has.</p>
<p>I've also observed that the engine seems to be running in nicely. <a href="https://incoherency.co.uk/blog/stories/calibrating-oscillating-engine-losses.html">Last time</a> it wouldn't
run below about 10 psi, but today I've noticed that it will run even at pressures low enough that the gauge reads 0.</p>
<p><h2>Electricity analogy</h2></p>
<p>I'm kind of getting into analogue electronics at the moment, and it's surprising how many ideas can carry over.</p>
<p>We can think of pressure as voltage and flow rate as current.</p>
<p>Restrictions to flow rate are the same as resistance. Reservoirs for air are a bit like capacitors (e.g. with one leg attached to ground: they can store up pressure
and release it later).</p>
<p>The engine presents an inductive load, just like an electric motor, because of the inertia of the flywheel (it wants to keep pulling air through even once the supply is switched off).</p>
<p>The supply hose acts like a wire with high resistance, and combined with the resistance presented
by the motor, at any given point in its cycle, they form a <a href="https://en.wikipedia.org/wiki/Voltage_divider">voltage divider</a>, which we are measuring with the pressure
sensor (i.e. voltmeter).</p>
<p>So then the issue with the pressure dropping when the port opens is just like <a href="https://en.wikipedia.org/wiki/Brownout_(electricity)">brownout</a> when
a circuit increases its current draw. The solution to brownout in electronics is to put a <a href="https://en.wikipedia.org/wiki/Decoupling_capacitor">bypass capacitor</a> near
the power input to the affected device, and the solution I have proposed for the engine is exactly the same: putting a "reservoir" near the inlet to the engine is the same
as adding a bypass capacitor.</p>
<p>For a better analogy to a capacitor, we'd probably want to make the reservoir out of a <i>balloon</i>. That way it is actually acting against the atmosphere (i.e. ground potential) instead
of just getting pressurised on its own. What we've got with a reservoir is basically like a capacitor that only has one terminal. Like a big metal plate hanging off a wire. I'm not actually sure
why a capacitor works more than twice as well as a single metal plate does. I should find out.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/measuring-wigwag-inlet-pressure.html</link>
   <guid>http://incoherency.co.uk/blog/stories/measuring-wigwag-inlet-pressure.html</guid>
   <pubDate>Mon, 17 Apr 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Calibrating losses in the oscillating engine simulator</title>
   <description><![CDATA[The biggest unknown variable in the oscillating engine simulator
is the amount of friction loss that an engine is likely to experience. To calibrate the simulation I have measured the speed of my engine at various supply pressures
and then simulated the same conditions, adjusting the simulated loss until the speed matches.]]></description>
   <content:encoded><![CDATA[<p>The biggest unknown variable in the <a href="https://incoherency.co.uk/oscillating-engine/">oscillating engine simulator</a>
is the amount of friction loss that an engine is likely to experience. To calibrate the simulation I have measured the speed of my engine at various supply pressures
and then simulated the same conditions, adjusting the simulated loss until the speed matches.</p>
<p>You may recall that my engine was not working very well because the port faces were not sitting flat. My Dad suggested
an easy fix would be to enlarge the pivot hole so that the spring is able to pull the faces together.
That's easier than anything else I had in mind, so I have done it. I only drilled it out by 0.2mm.
You can still hear air leaks when the engine stalls, which suggests there is still not a perfect seal, but that
is probably unavoidable.</p>
<p><h2>1. Gathering data</h2></p>
<p><h3>Methodology</h3></p>
<p>I set up a video camera pointing at the pressure gauge on the compressor, and within earshot of the engine. Using the view of the
pressure gauge I can tell what pressure is being supplied to the engine, and by counting pulses on the audio track I can tell
what speed the engine is running at. I adjusted the regulator to change the supplied pressure, and allowed the engine to run for a
few seconds to stabilise before adjusting the regulator again.</p>
<p>I then watched the video and noted down timestamps at which the engine speed was stable, along with the
corresponding pressure at that time. I then scrolled through the audio track in Audacity and counted the pulses.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4310"><img src="https://img.incoherency.co.uk/4310/thumb"></a><br>
<small>The highlighted portion corresponds to 5 revolutions. Audacity says the selection spans 512ms. 5 revolutions in 0.512 seconds = 9.77/sec = <b>586 rpm</b></small></p>
<p>My data is all in a <a href="https://github.com/jes/oscillating-engine/blob/master/loss-calibration.ods">LibreOffice spreadsheet</a> in case you want to look at it.
And the <a href="https://www.youtube.com/watch?v=8nPL7HZbTow">source video</a> is on YouTube.</p>
<p>My Wig-Wag is not built exactly to the drawings. The bore is 15.2 mm (+0.2mm vs spec), the length from the crank pin to the top of the piston is 61mm
(-2mm vs spec), and the gap above piston at top dead centre is 8mm (+3.25mm vs spec, I am as confused as you about where the extra 1.25mm has come from).</p>
<p><h3>Confounders</h3></p>
<p>That some air leaks out when the engine is stalled implies that the port face is not a perfect seal. This also implies that some air
leaks out while the engine is <i>not</i> stalled (but you can't hear it over the noise). But the simulation assumes the air path is perfectly sealed. Maybe
the simulation should gain a parameter to configure the diameter of a "leak hole" in the top of the cylinder, to simulate the leak
from the port faces.</p>
<p>It is likely that when the inlet port is open, the actual available pressure drops, but this
is not reflected in the gauge because of the length of hose in between the gauge and the engine. To find out, we should put a pressure gauge closer
to the engine.</p>
<p>The lowest marked point above 0 on the pressure gauge dial is 10 psi (~69 kPa), and the scale is very obviously linear everywhere except at the lower end,
where there is not much of a gap between 0 and 10 psi. This makes me suspect that the scale is not very accurate at the lower end, so the data I have
recorded is likely to be less accurate at lower pressures than at higher pressures.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4311"><img src="https://img.incoherency.co.uk/4311/thumb"></a></p>
<p><h3>Results</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/4308"><img src="https://img.incoherency.co.uk/4308/thumb"></a></p>
<p><h3>Evaluation</h3></p>
<p>For a sanity check, we can compare the qualitative shape of the curve to pressure-speed curves generated from the simulator, and find that it matches pretty well: as you increase the pressure more and more,
the engine speeds up less and less (diminishing returns). Also, the curve intersects the x axis and not the y axis, which means there is a minimum
pressure required for the engine to run, and it will not run at 0 pressure.</p>
<p><h2>2. Calibrating losses</h2></p>
<p><h3>Methodology</h3></p>
<p>For each of the air flow models in the simulator (TLV, Bill Hall, Trident 1, Trident 2, Bernoulli, Linear), and for supply pressures at 25 kPa intervals from
75 up to 275, I adjusted the simulated friction losses of the engine until the simulated engine was running at the same speed as the real engine.</p>
<p>Under the assumption everything else is accurate, we have thus determined the amount of friction losses that the real engine was suffering from at this speed.</p>
<p><h3>Results</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/4309"><img src="https://img.incoherency.co.uk/4309/thumb"></a></p>
<p><h3>Evaluation</h3></p>
<p>Aside from TLV and Linear, all of the other air flow models have regions where increasing the engine speed actually <i>decreases</i> the amount of friction. This
is intuitively tough to swallow, although you might be able to argue that some parts of the engine are transitioning from stick-slip to sliding
friction (maybe the port faces?).</p>
<p>I think this is not the reason. I think the problem is simply that those air flow models are too pessimistic about how quickly the air can flow in/out of the engine, so the
only way to make the speed match as pressure increases is to let them have less friction. The loss curves
for "TLV" (from <a href="https://www.tlv.com/global/UK/calculator/air-flow-rate-through-orifice.html">TLV</a>) and "Linear" (my uninformed guess at how air flow works) look
much more believable to me. Since the TLV model is from "A Steam Specialist Company", and the Linear model is pulled out of my bum, I'm going to say the TLV model is
probably the better one.</p>
<p>Currently the simulator only accepts a linear loss model (i.e. a static amount of loss, plus a loss that rises proportional to engine speed). I tried fitting
a quadratic curve to the loss data from the TLV model. It doesn't look exactly the right shape, but it is better than a straight line:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4312"><img src="https://img.incoherency.co.uk/4312/thumb"></a></p>
<p><h2>3. Conclusion</h2></p>
<p>The next things to try are:</p>
<p><ol>
<li>run the same measurement again but with a second pressure gauge, closer to the engine, to see how much the supply pressure actually drops when the port opens</li>
<li>add a "leak hole" to the simulator and see if adjusting the size of the leak hole can make the simulated engine better match the real one</li>
<li>make the simulator accept a quadratic loss model, and configure it according to the discovered curve above</li>
<li>absent any indication to the contrary: eventually remove all of the air flow models except for TLV</li>
</ol>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/calibrating-oscillating-engine-losses.html</link>
   <guid>http://incoherency.co.uk/blog/stories/calibrating-oscillating-engine-losses.html</guid>
   <pubDate>Thu, 13 Apr 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>My Wig-Wag</title>
   <description><![CDATA[I have finished building the Wig-Wag engine that I mentioned
in my post about the simulator,
and it runs! Great success.]]></description>
   <content:encoded><![CDATA[<p>I have finished building the <a href="https://wigwagengine.wixsite.com/wigwag">Wig-Wag engine</a> that I mentioned
in my post about the <a href="https://incoherency.co.uk/blog/stories/oscillating-engine-simulator.html">simulator</a>,
and it runs! Great success.</p>
<p>I made it with my <a href="https://incoherency.co.uk/blog/stories/mini-lathe-stand.html">mini lathe</a> and <a href="https://incoherency.co.uk/blog/stories/cnc-mini-mill.html">CNC mini mill</a>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4296"><img src="https://img.incoherency.co.uk/4296/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4297"><img src="https://img.incoherency.co.uk/4297/thumb"></a></p>
<p>I'm running it on compressed air rather than steam, purely for convenience. I'm more interested in the
engine than the steam for the time being (although I am a <i>bit</i> interested in the steam,
so maybe I will make a steam boiler one day).</p>
<p>I managed to fit the "pivot rod" to the cylinder out-of-square, which means the port face on the cylinder
does not sit flat against the port face on the main column. This is very bad because it means the
port faces only make contact in one corner, which leads to premature wear, and because the port face doesn't
seal very well, which wastes a load of air and reduces efficiency.</p>
<p>I did try to run the engine with the spring tensioner done up quite tightly to try and make it wear in, but this
was a bad idea and I have caused the two faces to gouge each other in the corner where they contact. Bad.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4298"><img src="https://img.incoherency.co.uk/4298/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4299"><img src="https://img.incoherency.co.uk/4299/thumb"></a></p>
<p>I believe the cause of the problem is that I didn't take enough care when tapping the female thread in the cylinder.</p>
<p>The solution will be to take the pivot rod out and either
make the thread a very loose fit and glue it in with Loctite such that it is square, or
re-machine the port face on the cylinder so that it is perpendicular to the threaded hole, or a bit of both.</p>
<p>Once I have made the engine run the way it should, the next step is to fit a pressure sensor to the top of the cylinder,
and some form of crank position sensor to the crankshaft, and plot pressure-volume diagrams from real life to
validate the accuracy of the simulation.</p>
<p>I have a video clip of my engine here:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/dAE3zGb_kEw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p><h2>Knurling</h2></p>
<p>The drawings call for the spring tensioner to have a knurled grip on it, but I do not
have any knurling tools. My solution was to use my homemade 4th axis to cut a diamond knurl pattern using
a 90-degree V-pointed cutting bit, and that worked pretty well:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4300"><img src="https://img.incoherency.co.uk/4300/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4302"><img src="https://img.incoherency.co.uk/4302/thumb"></a></p>
<p>I have a <a href="https://www.youtube.com/watch?v=0LSVeLIQ8OA">video clip of that process</a> too. It is
not a fast operation.</p>
<p><h2>Simulator</h2></p>
<p>There have also been quite a number of improvements to the simulator since last time, most notably it
now supports double-acting engines and it can now plot torque curves and pressure-speed curves, for example:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4301"><img src="https://img.incoherency.co.uk/4301/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/wig-wag.html</link>
   <guid>http://incoherency.co.uk/blog/stories/wig-wag.html</guid>
   <pubDate>Sat, 08 Apr 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Oscillating Engine Simulator</title>
   <description><![CDATA[I've been working on an oscillating engine
simulator. It's a type of steam engine where instead of valve gear, the cylinder swings back and forth, exposing a hole
in the cylinder to an inlet port for the power stroke, and to an exhaust port for the exhaust stroke. Very simple.
(I've also been working on building one, in the form of a Wig-Wag,
but I haven't got very far with that).]]></description>
   <content:encoded><![CDATA[<p>I've been working on an <a href="https://en.wikipedia.org/wiki/Oscillating_cylinder_steam_engine">oscillating engine</a>
simulator. It's a type of steam engine where instead of valve gear, the cylinder swings back and forth, exposing a hole
in the cylinder to an inlet port for the power stroke, and to an exhaust port for the exhaust stroke. Very simple.
(I've also been working on building one, in the form of a <a href="https://wigwagengine.wixsite.com/wigwag">Wig-Wag</a>,
but I haven't got very far with that).</p>
<p>You can <a href="https://incoherency.co.uk/oscillating-engine/">play with my simulator if you want</a>.</p>
<p>You might enjoy
trying to find an engine with the smallest displacement
that can provide at least 10 Watts of power at 50 kPa inlet pressure. You'll
need to adjust the "load" field to get some useful work out
(otherwise the engine will accelerate up to the point that the
work done is cancelled out by the losses), but
leave the "loss" and "air flow method" fields alone if you want to compare apples to
apples. The rest of the parameters are fair game. If you have a go, send me a screenshot of
your parameters, and if more than one person bothers then I'll publish
a league table next time.</p>
<p><a href="https://incoherency.co.uk/oscillating-engine/"><img src="https://img.incoherency.co.uk/4274/thumb"></a></p>
<p>The top group of parameters configures the engine. The bottom group of parameters configures
the environment and simulation.</p>
<p>The diagram of the engine includes a
representation of the air inside the cylinder, with the colour representing
its pressure. The colours drawn on the flywheel indicate the port timing (red means the
inlet port is open, blue means the exhaust port is open, and a fatter band
means it's open wider).</p>
<p>The plot on the right-hand side of the diagram is a
<a href="https://en.wikipedia.org/wiki/Pressure%E2%80%93volume_diagram">pressure-volume diagram</a>.</p>
<p>It could do with a bit more explanatory text and maybe a better UI, and probably a way
to share a link to a set of parameters. And probably some credit to the people whose
engine designs & data I have used.</p>
<p><h2>How it works</h2></p>
<p>The rendering is done with <a href="https://p5js.org/">p5.js</a>, which is only marginally
simpler than using the canvas directly.</p>
<p>The simulation is completely independent of the rendering, which will become important later
when I get around to using <a href="https://en.wikipedia.org/wiki/Simulated_annealing">simulated
annealing</a> to produce optimised engines. I hope to be able to improve on many of the
published designs.</p>
<p>I'm actually simulating the engine running on compressed air
rather than
steam. The difference is that with compressed air you don't need to worry (as much!) about the
effects of temperature change and condensation, so the simulation assumes the air remains at room temperature.</p>
<p>At every time step, it computes the mass of air that flows through the inlet
and exhaust ports (which can be 0, for example when they're closed, or when the pressure in the cylinder matches the pressure on the other side of the port). It computes the volume
in the cylinder based on the position of the piston. With the mass of air in the cylinder and the volume
known, the pressure can be computed. Knowing the pressure in the cylinder and the cross-sectional area
of the bore, you know the force on the piston. Knowing the force on the piston and the effective acting
radius of this force on the crank, you know the torque on the crank. Knowing the torque on the crank and the moment
of inertia of the flywheel, you can find the angular acceleration of the flywheel, which gives you
an updated angular velocity. With the new angular velocity, you can work out how far the crank has
rotated during this time step, which also gives you an updated piston position, and then
you're ready to start again at the next time step.</p>
<p>There are only 2 real complications: computing the air flow rate, and calibrating the losses.</p>
<p><h2>Air flow rate</h2></p>
<p>I am modelling the ports as a small orifice connecting the cylinder to an infinite volume of either
inlet pressure (for the inlet port) or atmospheric pressure (exhaust port). The cross-sectional area
of this orifice depends on the area of overlap between the cylinder port and the inlet/exhaust port, and can
be further reduced if the piston partially or completely blocks it off.</p>
<p>In the following image the inlet port (left hand one) partially overlaps the cylinder port, but the port is
completely blocked off by the piston so there is no air flow. The flywheel is rotating clockwise, which
means the piston is travelling down, which means the port is about to be uncovered, as you can see from the
approaching red area on the port timing diagram shown on the flywheel.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4275"><img src="https://img.incoherency.co.uk/4275/thumb"></a></p>
<p>This orifice-with-infinite-volumes model is not perfectly right, because even if an infinite volume of air <i>were</i> available
on each side, the port itself has nonzero length. It's more like a small <i>pipe</i> connecting the cylinder
to the infinite volume. It might be interesting to explore how the results from the simulation would
change if the port length were taken into account, but I haven't attempted to do so yet. I'm saying
that if your inlet suffers a significant pressure drop when air starts flowing through it, then that is an engine construction
problem outside the scope of the simulator.</p>
<p>But we still have the problem of actually calculating what the air flow through the orifice should be.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4276"><img src="https://img.incoherency.co.uk/4276/thumb"></a></p>
<p><h3>Linear</h3></p>
<p>My first guess was that the flow rate is simply linear in the pressure difference and the cross-sectional area,
and then I'd manually find a fudge factor that makes the performance look believable.
This is the "Linear" option in the simulator. It actually works surprisingly well, because as long as the engine
is running slow enough, the cylinder pressure adapts to the port pressure very quickly, and then there's no flow
rate. So as long as your flow rate calculation has high flow at high pressure differences and low flow at low
differences, it'll probably work reasonably well.
But it's possible to do better, so I sought improvements.</p>
<p><h3>Bernoulli's Equation</h3></p>
<p>My next attempt was from <a href="https://physics.stackexchange.com/a/131068">this Stack Exchange answer</a>
which says you can use Bernoulli's equation, which (rearranged) says that the velocity of the air through
the orifice is proportional to the <i>square root</i> of the pressure difference.</p>
<p>I'm not sure how reasonable this is because every other source on Bernoulli's Equation that I have looked at talks
about flows of liquid, not gas. I don't know enough about physics to judge. I also read that air flow can
be "choked" when the velocity meets the speed of sound, which means any further change in the pressure
difference can not increase the flow rate of the air. I hacked in a hard cut-off at the speed of sound,
but it seems unlikely that the change in flow velocity <i>truly</i> stops abruptly once it reaches the speed of sound,
so this is also probably wrong.</p>
<p><h3>Trident</h3></p>
<p>Trident Compressed Air Ltd. has <a href="https://trident.on.ca/engineering-information/airvacuum-flow-orifice-table/">a
helpful table</a> showing the flow rate of air through orifices of
different sizes, and at different pressures.</p>
<p>I assume the data from the table is accurate since they are an engineering company with "Compressed Air" literally in the
name. Sadly they don't provide any formulae, so it's hard to extrapolate beyond the range of pressures and orifice sizes
given.</p>
<p>I had 2 attempts at manually curve-fitting this data (these are the "Trident 1" and "Trident 2" air flow methods). They
are mostly very similar to each other but diverge quite a lot once the pressure difference drops below the minimum from
Trident's table.</p>
<p><h3>TLV</h3></p>
<p>My final air flow method
comes from TLV's <a href="https://www.tlv.com/global/TI/calculator/air-flow-rate-through-orifice.html">Air Flow Rate through an Orifice</a> calculator.</p>
<p>TLV is apparently
a "Steam Specialist Company" (and not of the video game variety)
so like Trident they are also likely to have accurate numbers,
but unlike Trident they show their working, so once I worked out
what all the parameters meant I was able to
lift TLV's formulae straight into the simulation.</p>
<p>They also have 2 different formulae based on whether or not
the ratio of the pressure difference to the primary pressure
exceeds the product of the specific heat ratio factor and the
pressure differential ratio factor (whatever that all means), which
I think accounts for the flow rate trailing off before reaching
the speed of sound.</p>
<p>At some point I will probably remove the "air flow method" option
and make it always use TLV.</p>
<p><h2>Losses</h2></p>
<p>I have 2 sources of data on losses.</p>
<p>I emailed <a href="http://www.steves-workshop.co.uk/">Steve Bodiley</a> about the simulator project, to inquire about
the piston on his <a href="http://www.steves-workshop.co.uk/steammodels/simpleoscil/simpleoscil.htm">Simple Oscillating Engine</a> covering up the ports as
it crosses top dead centre, and he has kindly sent me a spreadsheet of
torque measurements from running his engine connected up to a torque brake, which tell me the supply pressure, engine rpm,
and torque load for a handful of different conditions.</p>
<p>Secondly, I found <a href="https://www.youtube.com/watch?v=ix39UQ2dEFA">this video of a Wig-Wag running with a pressure
gauge visible</a>. Given the supply pressure (and finding the
engine speed from counting the pulses in the audio track), I
can set up the same conditions in the simulator and work out
how much load is required in the engine to produce the observed
running speed (rpm).</p>
<p>So far the best I've come up with is to say that there is a fixed
loss of 0.001 Nm of torque, plus a speed-dependent loss of 2.5*10<sup>-5</sup> Nm per rpm (i.e. friction losses increase as
speed increases).</p>
<p>This model doesn't fit the observations <i>particularly</i> well, and it is
probably the weakest part of the simulator. It would probably
benefit both from more data and a better model.</p>
<p><h2>Different types of steam engine</h2></p>
<p>You could simulate a multi-cylinder oscillating engine by simply
adding up the torque from each cylinder before applying the
update to the crank position.</p>
<p>It would be relatively straightforward to extend the simulator
 to handle other types of steam engine. I'd need to take out the
part that calculates port areas and replace it with something
specific to the valving of the different type of engine, and
the rest can stay the same.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/oscillating-engine-simulator.html</link>
   <guid>http://incoherency.co.uk/blog/stories/oscillating-engine-simulator.html</guid>
   <pubDate>Sun, 19 Mar 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>My mini lathe stand</title>
   <description><![CDATA[I'm working through the book
Lathework: a complete course,
and it is suggested that benchtop lathes really need to be
bolted to something sturdy in order to do accurate work, because they lack the required rigidity. Bolting to
a plywood workbench is not enough, because to make the lathe turn parallel you need to adjust the mounting to take the twist
out of the ways, which means the stand needs to be broadly as strong as the lathe bed otherwise you will twist the
stand instead of the bed.]]></description>
   <content:encoded><![CDATA[<p>I'm working through the book
<a href="https://www.amazon.co.uk/Lathework-Complete-Course-Workshop-Practice/dp/1854862308">Lathework: a complete course</a>,
and it is suggested that benchtop lathes really need to be
bolted to something sturdy in order to do accurate work, because they lack the required rigidity. Bolting to
a plywood workbench is not enough, because to make the lathe turn parallel you need to adjust the mounting to take the twist
out of the ways, which means the stand needs to be broadly as strong as the lathe bed otherwise you will twist the
stand instead of the bed.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4248"><img src="https://img.incoherency.co.uk/4248/thumb"></a></p>
<p>The stand I have built is a "spanning beam" stand, which means the lathe is bolted to a beam which is only supported
at the ends. Supporting the beam in the middle is supposedly to be avoided, because if supported in the middle it is possible for the beam to
be bent by changes in the load distribution, whereas 2 points always describe a straight line. However for my purposes I
think it wouldn't make any difference.</p>
<p>There is a good page about making such a stand, along with several examples: <a href="https://web.archive.org/web/20230714024901/http://users.tpg.com.au/agnet/cq9325rev4.html">Make a spanning beam metal lathe stand easily</a>.</p>
<p>A while ago I removed some old gates and kept them around for the steel tubing:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4204"><img src="https://img.incoherency.co.uk/4204/thumb"></a></p>
<p>I prefer using box section because then you don't have to notch the tubes, but it's hard to beat free.</p>
<p>Spend a few hours cutting the welds off, grinding them back, stripping the paint with a wire wheel, and cleaning
up the big dusty mess of rust and bits of old paint, and you have a collection of usable tubes:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4205"><img src="https://img.incoherency.co.uk/4205/thumb"></a></p>
<p>I was surprised to find that some of the tubes had been galvanised before they were painted and some had not, also some of them
had welded joints in the middle. Were these gates DIY'd by someone who had themselves rescued the tubes from something else? I
wonder what previous life they had. I wonder what future lives they may have.</p>
<p>I didn't take any pictures of making the actual beam. As you can see, it is a piece of rectangular box section with some thick lugs
welded into it. (This was not part of the steel gates, it is steel I bought for the <a href="https://incoherency.co.uk/blog/stories/blmra-12-hour-2018.html">racing mower
front axle</a> but ended up not using).</p>
<p>I laid out a "jig" for welding the end supports on a piece of MDF:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4251"><img src="https://img.incoherency.co.uk/4251/thumb"></a></p>
<p>This worked quite well, and I got a nice matching pair of supports:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4224"><img src="https://img.incoherency.co.uk/4224/thumb"></a></p>
<p>Welding the rest of it together in thin air was a bit more Heath Robinson, but eventually I arrived at this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4229"><img src="https://img.incoherency.co.uk/4229/thumb"></a></p>
<p>There are nuts welded into the bottom of each tube, to provide for the leveling feet.</p>
<p>It is painted in silver Hammerite paint:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4230"><img src="https://img.incoherency.co.uk/4230/thumb"></a></p>
<p>The paint is meant to have a hammered effect, but I would describe the effect as "subtle".</p>
<p>And here is the stand installed, with the lathe bolted to the top:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4231"><img src="https://img.incoherency.co.uk/4231/thumb"></a></p>
<p>My garage floor is not very level (compare the adjustment of the leveling bolt on the rear left corner to the front right corner).</p>
<p>Around this time Emma and I tore down an old shed, and I managed to salvage a couple of big sheets of OSB, from which I made
shelves for the lathe stand. I prefer plywood, but again it's hard to beat free.</p>
<p>The idea is that the bottom shelf would just be used for storage, and the top shelf would be used as a working surface, and would
likely collect lots of swarf. To make the OSB more palatable as a working surface, and to aid sweeping of swarf, I decided to seal
the surface with a healthy coat of PVA:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4232"><img src="https://img.incoherency.co.uk/4232/thumb"></a></p>
<p>I came back out the next day, ready to fit my shelf, but it still wasn't dry:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4233"><img src="https://img.incoherency.co.uk/4233/thumb"></a></p>
<p>I suggest if you are going to do similar you should probably dilute the PVA with water. I left it by a radiator for another
day and it eventually dried to my satisfaction.</p>
<p>The top shelf is mounted with screws through the steel tubes. The bottom shelf just sits there under gravity.
Since the OSB is a bit too thin to be used unsupported, I have doubled up on the material to stiffen it up, with the top layer
spanning across the steel tubes, and the bottom layer sitting between them, like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4254"><img src="https://img.incoherency.co.uk/4254/thumb"></a></p>
<p>With the shelves installed, the first lathe job was to make some nylon bungs to block up the tops of the exposed tubes:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4252"><img src="https://img.incoherency.co.uk/4252/thumb"></a></p>
<p>And finally an Ikea "Helmer" drawer cabinet screwed down to the lower shelf to house the various lathe paraphernalia:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4248"><img src="https://img.incoherency.co.uk/4248/thumb"></a></p>
<p>(Yes, I deliberately spaced the horizontal tubes exactly far enough apart to fit a Helmer cabinet. I really like the Helmer cabinets. I have 4.)</p>
<p>I'm still working on the first project in the lathework book (it's a "mini surface gauge", you can see a drawing of one of the parts
on the wall behind the lathe),
and so far I have found using a dedicated stand to be much more convenient than dragging the lathe out and plonking it on the
workbench, although I can't say I've noticed any performance improvement from the increased rigidity.
But the <i>second</i> project in the book involves measuring and correcting the twist in the bed so that it turns accurately parallel,
which is when my lathe stand will really prove its worth.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/mini-lathe-stand.html</link>
   <guid>http://incoherency.co.uk/blog/stories/mini-lathe-stand.html</guid>
   <pubDate>Sat, 25 Feb 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Prime Combination: Solution</title>
   <description><![CDATA[One solution to the Prime Combination puzzle is
00001 ->
00002 ->
00003 ->
00013 ->
09013 ->
99013 ->
99023 ->
99923 ->
99823 ->
99833 ->
09833 ->
09733 ->
00733 ->
10733 ->
10723.]]></description>
   <content:encoded><![CDATA[<p>One solution to the <a href="https://incoherency.co.uk/blog/stories/prime-combination.html">Prime Combination</a> puzzle is
00001 ->
00002 ->
00003 ->
00013 ->
09013 ->
99013 ->
99023 ->
99923 ->
99823 ->
99833 ->
09833 ->
09733 ->
00733 ->
10733 ->
10723.</p>
<p><h2>Mandatory move to 00003</h2></p>
<p>There is a relatively straightforward argument that the first moves <i>must</i> be 00001 -> 00002 -> 00003. Consider:</p>
<p><ol>
<li>To turn the last digit into a 3 it has to come from either 2 or 4.</li>
<li>The only prime ending in 2 or 4 is 00002.</li>
<li>Therefore the only way to get a 3 in the final position is 00002 -> 00003.</li>
</ol></p>
<p>This cuts down the space of prime numbers we need to search quite considerably, because we only need to consider the ones
that end in a 3 (which is only 2402 of the 9592 primes that fit in 5 digits).</p>
<p><h2>A map</h2></p>
<p>Here's a map of the entire search space, generated with <a href="https://graphviz.org/">graphviz</a>:</p>
<p><a class="img" href="https://incoherency.co.uk/interest/prime-combination.svg"><img style="max-width:100%" src="https://img.incoherency.co.uk/4208"></a><br>
<small>(Click to view large SVG - I suggest zoom out to a level that fits the entire thing on the screen at once)</small></p>
<p>00001 is at the top and 10723 is the lowest point on the right-hand side.</p>
<p>(I've omitted the arrows that point from every node to 00001.)</p>
<p>The puzzle about the combination lock
is isomorphic to pathfinding from
00001 to 10723 on this graph.</p>
<p>I think the graph is small enough (and is laid out sensibly enough)
that manual pathfinding is doable, however I think creating the graph
by hand would be too much trouble, so I don't think the puzzle is readily
solvable by hand in a sensible amount of time.</p>
<p><h2>Mandatory move to 00013?</h2></p>
<p>We already have a proof that it is mandatory to pass through 00003. From
looking at the map it is easy to see that it is also mandatory to pass
through 00013 if you want to access the subgraph that leads to 10723.</p>
<p>Is there a reasonably straightforward argument that the route must pass
through 00013 (along the lines of the argument about 00003) or is it just
a very lengthy process of elimination?</p>
<p><h2>Why start on 00001?</h2></p>
<p>I originally wanted to start the combination on 00000, but it took me far
too long to realise that there are no legal moves. 00001 is the next
obvious choice.</p>
<p>It is kind of unpleasant that 00001 is the sole reachable state that is
not prime, but if the start state were 00002 instead then the entire left
half of the search space (as shown in the map) would be unreachable. I prefer
it this way.</p>
<p><h2>Adventure game</h2></p>
<p>We could imagine using the map to create a text adventure. The simplest way
is to just make an ordinary game and connect up the map of the game in
the same way as the graph of Prime Combination. Compare to
<a href="http://blog.zarfhome.com/2023/02/a-treasury-of-zork-maps.html">A treasury of Zork maps</a>.</p>
<p>But we can view
the digits of the nodes as integer coordinates in a 10x10x10x10x10 5-dimensional hypercube
(or, a 5-dimensional hypertorus, since the edges wrap) and then the
game is maybe to work out the general rule that decides which movements are
legal?</p>
<p>Or maybe you spawn at a random place in the map and you have to work out where
you are, without knowing your coordinates, based only on moving around and
noting which passageways are open?</p>
<p><h2>Big map</h2></p>
<p>I have a much bigger map of the entire space of prime connections. It includes
the isolated subgraphs that can't be reached from 00001. It's at
<a href="https://incoherency.co.uk/interest/prime-combination-big.svg">https://incoherency.co.uk/interest/prime-combination-big.svg</a> (warning: 5 megabyte SVG, may lag your comp - I suggest zoom out to a sensible level and then scroll horizontally).</p>
<p>This map contains 2735 separate connected components of 2 or more nodes. There are also 8402 individual primes not shown, which aren't connected to any others.
Of the 2735 components, 450 only contain 2 nodes. There are 172 that have more than 10 nodes.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/prime-combination-solution.html</link>
   <guid>http://incoherency.co.uk/blog/stories/prime-combination-solution.html</guid>
   <pubDate>Sat, 11 Feb 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Prime Combination</title>
   <description><![CDATA[You come across a 5-digit combination padlock. The combination is 10723. The padlock is currently showing 00001.
If the combination is ever set to a number that is not prime, it resets to 00001 immediately, so every intermediate state from 00001 to 10723 also must be prime.
How do you input the combination?]]></description>
   <content:encoded><![CDATA[<p>You come across a 5-digit combination padlock. The combination is 10723. The padlock is currently showing 00001.
If the combination is ever set to a number that is not prime, it resets to 00001 immediately, so every intermediate state from 00001 to 10723 also must be prime.
How do you input the combination?</p>
<p><ul>
<li>The input wheels are arranged in the usual way: 5 positions with digits 0 to 9, decrementing from 0 gets you to 9, incrementing from 9 gets you to 0.</li>
<li>There is a mechanism that prevents you from turning more than 1 wheel at a time.</li>
<li>If you try to park a digit halfway between 2 values it springs back to one of the values before you are able to change another digit.</li>
</ul></p>
<p>I have posted <a href="https://incoherency.co.uk/blog/stories/prime-combination-solution.html">a solution and some analysis</a>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/prime-combination.html</link>
   <guid>http://incoherency.co.uk/blog/stories/prime-combination.html</guid>
   <pubDate>Sun, 05 Feb 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Optimal eccentric-weighted coins</title>
   <description><![CDATA[If you wanted to make a hole in a coin so that the centre of mass is moved as far away from the
original centre as possible, how big a hole would you make and where would you put it?]]></description>
   <content:encoded><![CDATA[<p>If you wanted to make a hole in a coin so that the centre of mass is moved as far away from the
original centre as possible, how big a hole would you make and where would you put it?</p>
<p>This is quite reminiscent of the <a href="https://physics.stackexchange.com/questions/161468/center-of-mass-of-a-soda-can#161487">"Centre of mass of a soda can" problem</a>, which asks how the centre of mass of a can of drink changes as the drink is consumed. (You might enjoy giving it some thought if you haven't seen the problem before).</p>
<p><a class="img" href="https://img.incoherency.co.uk/4144"><img style="max-width:400px; max-height:400px" src="https://img.incoherency.co.uk/4144"></a></p>
<p><h2>Wall thickness</h2></p>
<p>We want the outer circumference of the coin to be retained, which means we can't drill the hole right at the edge. We need some minimum
wall thickness, otherwise we don't have a coin any more, we have more of a crescent moon.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4141"><img style="max-width:300px; max-height:300px" src="https://img.incoherency.co.uk/4141"></a>
<a class="img" href="https://img.incoherency.co.uk/4145"><img style="max-width:300px; max-height:300px" src="https://img.incoherency.co.uk/4145"></a></p>
<p><h2>Limit cases</h2></p>
<p>The limit cases are:</p>
<p>1.) 0-sized hole: we can trivially see that this does not affect the mass at all, the centre of which remains in the centre.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4146"><img style="max-width:300px; max-height:300px" src="https://img.incoherency.co.uk/4146"></a></p>
<p>2.) Maximum-sized hole: this leaves us with a symmetrical ring, with the centre of mass also in the centre.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4147"><img style="max-width:300px; max-height:300px" src="https://img.incoherency.co.uk/4147"></a></p>
<p><h2>Hole locations</h2></p>
<p>We can also see that for any size of hole, if the hole does not touch the perimeter (modulo the minimum wall thickness), then we can produce
a corresponding coin with the same-sized hole, where the hole does touch the perimeter, and this second coin will have a more eccentric centre
of mass than the first.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4148"><img style="max-width:300px; max-height:300px" src="https://img.incoherency.co.uk/4148"></a>
<a class="img" href="https://img.incoherency.co.uk/4141"><img style="max-width:300px; max-height:300px" src="https://img.incoherency.co.uk/4141"></a></p>
<p><h2>Maths</h2></p>
<p>So for a given coin radius (<b><i>r<sub>coin</sub></i></b>) and minimum wall thickness (<b><i>w</i></b>), we only have one variable: the radius of the hole (<b><i>r<sub>hole</sub></i></b>). We'll work with radii instead of diameters because it makes the maths easier.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4151"><img style="max-width:300px; max-height:300px" src="https://img.incoherency.co.uk/4151"></a></p>
<p>Since we're looking at a 2-dimensional cross section, the mass of the coin is proportional to the area of the shape in cross section.</p>
<p>So the mass of the original coin is proportional to its area, <b><i>m<sub>coin</sub> = &pi;r<sub>coin</sub><sup>2</sup></i></b>.</p>
<p>The mass removed when we drilled the hole is proportional to the hole's area, <b><i>m<sub>hole</sub> = &pi;r<sub>hole</sub><sup>2</sup></i></b>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4150"><img style="max-width:300px; max-height:300px" src="https://img.incoherency.co.uk/4150"></a></p>
<p>To leave a gap of <b><i>w</i></b> between the circumference of the hole and the circumference of the coin, <b><i>y = r<sub>coin</sub> - r<sub>hole</sub> - w</i></b>.</p>
<p>And to work out where the resulting centre of mass lies, we'll say the coin is a body at the origin, with a mass of <b><i>m<sub>coin</sub></i></b>, and we'll say the hole 
is a second body with (negative) mass <b><i>-m<sub>hole</sub></i></b>, positioned with its centre at a distance of <b><i>y</i></b> away from the centre of the coin.</p>
<p>Weighting the mass of the hole by its location, the radial position of the centre of mass is therefore <b><i>r<sub>mass</sub> = m<sub>hole</sub> * y / (m<sub>coin</sub> - m<sub>hole</sub>)</i></b></p>
<p>So <b><i>r<sub>mass</sub> = &pi;r<sub>hole</sub><sup>2</sup> * (r<sub>coin</sub> - r<sub>hole</sub> - w) / (&pi;r<sub>coin</sub><sup>2</sup> - &pi;r<sub>hole</sub><sup>2</sup>) = r<sub>hole</sub><sup>2</sup> * (r<sub>coin</sub> - r<sub>hole</sub> - w) / (r<sub>coin</sub><sup>2</sup> - r<sub>hole</sub><sup>2</sup>)</i></b>.</p>
<p>To work out where <b><i>r<sub>mass</i></b> is maximised, we can find the partial derivative of this function with respect to <b><i>r<sub>hole</sub></i></b> and solve <b><i>r<sub>mass</sub>' = 0</i></b>.</p>
<p>...at least, that was the plan, but differentiating that function proved too inconvenient.</p>
<p>So let's lose a variable: scale everything so that it's proportional to <b><i>r<sub>coin</sub></i></b>. Now we have:</p>
<p><b><i>R<sub>coin</sub> = 1</i></b><br>
<b><i>R<sub>hole</sub> = r<sub>hole</sub> / r<sub>coin</sub></i></b><br>
<b><i>W = w / r<sub>coin</sub></i></b><br>
<b><i>r<sub>mass</sub> = R<sub>mass</sub> * r<sub>coin</sub></i></b><br>
<b><i>R<sub>mass</sub> = R<sub>hole</sub><sup>2</sup> * (1 - R<sub>hole</sub> - W) / (1 - R<sub>hole</sub><sup>2</sup>)</i></b><br></p>
<p>This is still too difficult for me to differentiate by hand. With variable names substituted for single letters, WolframAlpha gives:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4155"><img src="https://img.incoherency.co.uk/4155/thumb"></a></p>
<p>and</p>
<p><a class="img" href="https://img.incoherency.co.uk/4156"><img src="https://img.incoherency.co.uk/4156/thumb"></a></p>
<p>Which is... not what I was hoping for. Did I make a mistake?</p>
<p><h2>Charts</h2></p>
<p>I gave up on trying to find a closed-form solution at this point and brute-forced it with a spreadsheet, for <b><i>W=0.1</i></b>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4157"><img src="https://img.incoherency.co.uk/4157/thumb"></a></p>
<p>When the minimum wall thickness is 10% of the radius of the coin, the optimum eccentricity (with centre of mass almost 20% out from the centre) is achieved when the radius of the hole is about 73% of the radius of the coin, which looks about like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4158"><img style="max-width:300px; max-height:300px" src="https://img.incoherency.co.uk/4158"></a></p>
<p>That's a much bigger hole than I expected! That's why it's important to calculate these things rather than guessing.
Looking at the shape of the chart, we also see that if there is likely
to be some error in the size of the hole, it's best to err on the side of making the hole too small than too large.</p>
<p><b><i>W=0.1</i></b> corresponds to a 1mm wall thickness on a 20mm diameter (10mm radius) coin, which I think is pretty reasonable. But how much is that
limiting us? How much better does our eccentricity get if we allow a slightly smaller wall thickness?</p>
<p><a class="img" href="https://img.incoherency.co.uk/4159"><img src="https://img.incoherency.co.uk/4159/thumb"></a></p>
<p>Centre of mass now almost 27% out from the centre, or about 35% better. And here are the two implied optimal coins, overlaid, and with centres of mass marked:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4161"><img style="max-width:400px; max-height:400px" src="https://img.incoherency.co.uk/4161"></a><br>
<small>(<b><i>W=0.1</i></b> in black, <b><i>W=0.05</i></b> in red, "+" marks centre of original coin, dots mark centres of mass)</small></p>
<p><h2>Conclusions</h2></p>
<p>1.) Always position the hole as close to the edge as possible.</p>
<p>2.) For a 1mm wall on a 20mm coin, drill a ~14.5mm hole. The resulting centre of mass will be about 2mm away from the centre point of the coin.</p>
<p>3.) For a 0.5mm wall on a 20mm coin, drill a ~16mm hole. The resulting centre of mass will be about 2.6mm away from the centre point of the coin.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/optimal-eccentric-weighted-coins.html</link>
   <guid>http://incoherency.co.uk/blog/stories/optimal-eccentric-weighted-coins.html</guid>
   <pubDate>Thu, 12 Jan 2023 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Problems with Protohackers</title>
   <description><![CDATA[This is a list of things wrong with Protohackers,
and my thoughts on what to do about them.]]></description>
   <content:encoded><![CDATA[<p>This is a list of things wrong with <a href="https://protohackers.com/">Protohackers</a>,
and my thoughts on what to do about them.</p>
<p><h2>1. Docker</h2></p>
<p>Protohackers is the second "important" service I've deployed with Docker, and the second time I've regretted it.</p>
<p>The big problem is that there's a short period of unnecessary downtime on every deployment.</p>
<p>The API server is a <a href="https://mojolicious.org/">Mojolicious</a> application running under
<a href="https://docs.mojolicious.org/Mojo/Server/Hypnotoad">hypnotoad</a>. Hypnotoad supports downtime-free
deployments out of the box. Just run <tt>hypnotoad foo</tt>, and the running instance of <tt>foo</tt> is
gracefully upgraded to the new version on disk. Great success. Only it doesn't work if your application
is running in Docker, because Docker containers are meant to be immutable. So instead of updating your
program code and asking hypnotoad to restart it, you have to stop the container and start a new one, and
the application is down in the meantime.</p>
<p>The user-facing website is a <a href="https://nextjs.org/">Next.js</a> site, compiled to a static site
and served from nginx. This should be easy-mode for downtime-free deployments! Just replace the site content
and <i>do nothing else</i> and nginx will start serving the fresh content. Sadly, the website is <i>also</i>
deployed as a Docker container (running nginx inside the container to serve the static site), so when the site
needs to be updated, the container needs to be stopped and a new one needs to be started.</p>
<p>The solution checker is a Perl daemon that consumes jobs from a beanstalk tube and executes individual problem checker
scripts, depending on the problem. Most of the time I'm changing the individual checker scripts rather than the "orchestrator",
so most upgrades would be free here, if only I were updating the files in the container instead of destroying the
container and making a new one. (Even if I need to update the "orchestrator" part, that should be trivial: I could
start an instance of the new checker and send a signal to the old one to tell it to finish up its existing jobs, not
reserve any new jobs, and exit when done - this would also work with Docker but is inconvenient to do with <tt>docker-compose</tt>).</p>
<p>So every significant component of my application can in principle be deployed with no downtime, and yet the website
is going down for 30 seconds every time I fix a typo in the problem text. For what?</p>
<p>The benefits of using Docker are that it simplifies daemon supervision (compared to writing systemd units or something), and
it makes sure that the versions of dependencies are the same in development as they are in production. But writing systemd units
is only a 1-time effort, and not substantially more complicated than writing a <tt>docker-compose.yml</tt>. And maybe I
don't care too much about keeping dependency versions in sync? So I think the plan is to move away from Docker and just run
everything directly on Linux, with shell scripts to handle deployments.</p>
<p><h2>2. Problem statements</h2></p>
<p>Every problem statement so far has had some part that is ambiguous or misleading.</p>
<p>It's very difficult for me to dispassionately read the problem statement without already knowing anything about
the protocol it is trying to specify, so I end up not writing down all of my assumptions.
Different people have different
preconceptions about how a protocol is likely to work. For example, I might assume things like:</p>
<p><ul>
<li>a request-response protocol can have multiple requests on a single session</li>
<li>when lines are separated by "\n", the final line has to end in a "\n" as well</li>
<li>byte order in network protocols is always big-endian</li>
<li>the important abstraction of a TCP-like protocol is a byte stream, not a packet stream</li>
<li>when measuring the length of a payload, you want to count the length of actual data <i>after</i> interpreting escape sequences</li>
</ul></p>
<p>And someone else might have different preconceptions. A good problem statement makes these assumptions explicit, but
it's hard to think of all the things that you are taking for granted, whilst you're taking them for granted.</p>
<p>I expect the thing to do is to recruit a playtester or two to read the problem statements before they're released,
implement a solution, and then tell me what was ambiguous or misleading. If you want to do it, get in touch.
The upside is that you get to solve the problems sooner than everyone else, and you get to contribute to making
the problems better. The downsides are that you aren't allowed
to talk to anyone about the problems until after they're released, and you aren't allowed on the leaderboard. And I
can't pay you (yet).</p>
<p><h2>3. Checker error messages</h2></p>
<p>People consistently complain that the error messages from the checker are not clear enough. This is quite frustrating,
as I actually do go out of my way to make the error messages helpful, it's just that there are a lot of different ways
to fail the checks, and I don't have time to make them all maximally helpful. Most users only ever encounter a small
subset of the possible error messages, and obviously they think that those particular messages should have more work put into
them. (And probably they're right).</p>
<p>Quite often the problem is that the user has sent a string of text (maybe thousands of characters long) that is not correct.
Just printing out both strings and saying they're different is not likely to be substantially helpful when they're longer
than trivial examples.
So I think I want a general-purpose string diffing function that finds the first difference in 2 strings and elucidates
it succinctly. That wouldn't be massively complicated to do.</p>
<p>Apart from that, another common problem is that the user has sent a binary object with a field or two missing,
so the checker is stuck waiting for more bytes before it decides what to do. Maybe at the point that the check times out
it would be useful if it dumped some information about the contents of its buffers. This isn't super easy to do, because
the timeout is handled at a different layer, but it would be possible. At least it would be useful to somehow give an indication
when the checker has received a partial message and is waiting for more. It's quite tricky to think of a general-case
solution here, it would have to work differently for every problem.</p>
<p>I think if I get a playtester or two, they're likely to have suggestions about the error messages that they encounter
during testing, so that would help me work on the error messages more effectively.</p>
<p>Another view is that the checker shouldn't be providing useful error messages <i>at all</i>! The users should debug their own
applications by looking at what they're actually sending and receiving and comparing it to what they expect. Having the
checker provide "useful" error messages just causes the users to treat the checker as an automatic debugger, and then
get frustrated when it doesn't work by magic. Maybe it would be better if the error messages were actually <i>worse</i>,
and there was a tacit understanding that debugging the program is the user's problem rather than the checker's.</p>
<p><h2>4. Frequency of problems</h2></p>
<p>Making the problems is quite time-consuming.
I was planning to do one problem every 2 weeks, but I've pushed the next one
out to 3 weeks away, and it might turn into every 3 weeks now.</p>
<p>I originally picked a 2-week period because that makes 26 problems a year, and <a href="https://adventofcode.com/">Advent of Code</a>
has 25 problems a year, so I thought
it would be in the ballpark of reasonability. But the amount of time I spend on making Protohackers problems has given
me a newfound appreciation for how hard Eric Wastl must work on Advent of Code.</p>
<p>Coming up with problem ideas hasn't been too hard, because I still haven't run out
of principles that I want to cover. And writing a reference solution for each problem isn't
too hard either. The hard parts are 1.) trying to make a checker that checks all of the important parts
of the problem, without assuming any behaviour specific to my reference solution, and 2.) trying to write a problem statement that
accurately and succinctly conveys the protocol specification, with every important behaviour explicitly documented.</p>
<p><h2>5. User acquisition</h2></p>
<p>There are 852 user accounts at the moment, of whom 399 have completed any problem, of whom 261 have solved any non-echo-server problem.</p>
<p>I don't know how most people are finding the site. I'm not advertising anywhere. It would be good to be more purposeful about
attracting new users, but I don't have any great ideas. I <a href="https://twitter.com/Protohackerscom">Tweet</a>, a little bit, but the
Twitter account only has 74 followers so I don't think it does a lot of good. I emailed a handful of programming newsletters to
ask if they would mention it, but none of them were interested.</p>
<p>I need better ideas here.</p>
<p><h2>6. Monetisation</h2></p>
<p>Apart from being annoyed by the ambiguous problem statements and confusing error messages, people <i>like</i> Protohackers,
and frequently tell me so. If you've made something people like, then you've <a href="http://www.paulgraham.com/wealth.html">created
wealth</a> and should try to keep some of it for yourself in the form of cash. This would also allow me to pay
any would-be playtesters without feeling like I was throwing money in a hole.</p>
<p>So I'd love to make money out of Protohackers, but I'm not sure how viable it is until there are a lot more users. Ideas include:</p>
<p><h3>Ask the users to pay</h3></p>
<p>A couple of people have already offered to make a donation, but I don't have a good way to accept ad hoc donations,
and I don't want people to feel <i>obliged</i> to donate. Maybe I could set up a Patreon, but I can't see more than 5% of
people wanting to pay anything, and 5% of 260 arguably-active users is, like, 13 people? Paying a few quid a month?
Doesn't seem worth it.</p>
<p><h3>Sell merchandise</h3></p>
<p>I'm very picky about clothing quality, and can't recall ever buying branded merchandise that
I was actually satisfied with, so I'd probably spend a lot of time and money trying out different suppliers.
It also has the same problem as "asking users to pay" where I'll earn a tiny amount
of money each from a tiny handful of people, so it's not really worth doing.</p>
<p><h3>Solicit recruitment ads</h3></p>
<p>I think the best option is recruitment ads. The Protohackers userbase is highly targeted towards competent programmers,
and in particular success at Protohackers implies competency at network programming, and I imagine hiring competent
network programmers is <i>incredibly</i> valuable to some tech companies. Much more valuable than anything else I can
imagine anyone wanting to advertise on Protohackers.</p>
<p>So putting recruitment ads on the site is probably the best idea. Then the problem becomes who exactly wants to recruit
network programmers? How do I contact them? How much do they want to pay?</p>
<p>So if <i>you</i> want to advertise on Protohackers, or you know someone who might, please get in touch.
For the time being, you can simply
thumb down the <a href="https://protohackers.com/leaderboard">leaderboard</a>, click on the GitHub links, and contact
people yourself without paying me anything.
You would only want to pay if you want to invest in a
recruitment <i>pipeline</i>, rather than a 1-time mailshot to a handful of candidates.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/protohackers-problems.html</link>
   <guid>http://incoherency.co.uk/blog/stories/protohackers-problems.html</guid>
   <pubDate>Fri, 18 Nov 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Classifying minds</title>
   <description><![CDATA[Trying to learn about the mind by analysing the brain is like trying to learn about software by analysing the computer.
The only reason anybody thinks
neuroscience is related to minds is because we're not familiar with minds that aren't made out of brains.
But brains are just
the mechanism that evolution landed on, they're not fundamental. Our planes don't fly the same way birds do, and attempts to
discover principles of flight by analysing birds were not successful. Flight is actually much simpler than birds!
Maybe the principles of consciousness are much simpler than brains.]]></description>
   <content:encoded><![CDATA[<p>Trying to learn about the mind by analysing the brain is like trying to learn about software by analysing the computer.
The only reason anybody thinks
neuroscience is related to minds is because we're not familiar with minds that aren't made out of brains.
But brains are just
the mechanism that evolution landed on, they're not fundamental. Our planes don't fly the same way birds do, and attempts to
discover principles of flight by analysing birds were not successful. Flight is actually much simpler than birds!
Maybe the principles of consciousness are much simpler than brains.</p>
<p>Here's a rough sketch of the stack that implements human minds:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4066"><img src="https://img.incoherency.co.uk/4066/thumb"></a></p>
<p>We are approaching the problem from two different directions. We can study the physical properties of the brain (working upwards), and we
can introspect on thoughts (working downwards). You'd think this would allow us to meet in the middle and understand the system
all the way to the bottom.</p>
<p>Sadly not. The cloudy "???" section may have <i>unimaginable</i> complexity that is neither physically a part of the brain, nor
accessible to introspection. Just imagine trying to understand how a web browser works if you understand
nothing beyond electronic logic gates, except that you get to point and click in the GUI.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4068"><img src="https://img.incoherency.co.uk/4068/thumb"></a></p>
<p>You would have <i>no idea</i> about the unimaginable tower of software complexity sitting underneath Firefox, and no studying
of logic gates will explain it. Firefox seems to behave like a completely different type of thing to logic gates. And it <i>is</i>
a completely different type of thing. You need to understand an enormous stack of abstractions before you can comprehend Firefox
in terms of logic gates.</p>
<p>I think trying to understand the mind in terms of neuroscience similarly disregards the tower
of complexity that lies in the cloudy "???" zone.</p>
<p>Furthermore, the transistors and the logic gates are <i>not necessary</i> for Firefox to function. They're just a substrate on
which we can perform computation. Any substrate would do! Similarly, I think brains and neurons are not necessary for minds to function: they're just
a substrate which can interface between biology and whatever magical yet-to-be-discovered abstractions lie in the "???" layer.</p>
<p>And you may think that understanding those abstractions must be very complicated.
Well, the way birds work is very complicated, but the principles of flight are not, and flight only <i>seems</i> complicated
if you try to understand it by trying to understand birds.</p>
<p>So if not neuroscience, then who <i>will</i> help us with the hard problem of consciousness? I think the problem lies at the
intersection of computer science and philosophy. The "mind" part is very obviously the domain of philosophy. I think that if you work
your way upwards from "neuroscience", you eventually derive a <i>biological implementation of computer science</i>, and then you're stuck again.</p>
<p>Why do I think that? I claim that a brain is <i>purely an information-processing machine</i>. (If you disagree, your counter-argument
should probably start by outlining some proposed input or output of the brain that it would not be possible to encode numerically).</p>
<p>We know from the <a href="https://en.wikipedia.org/wiki/Church%E2%80%93Turing_thesis">Church-Turing thesis</a> that general-purpose computers
can compute all computable functions. Since the brain is (I claim) just computing a function, all of the operations of
a brain can be performed by general-purpose computers. And since (I claim) the mind is implemented on the brain, it therefore must
be possible to implement a mind in software. I <a href="https://incoherency.co.uk/blog/stories/consciousness-is-computable.html">doubted this before</a>
but I am a believer now.</p>
<p>So let's skip all the hard work of explaining how neuroscience creates computer science (a worthy and interesting field of study,
no doubt, but not the one I'm interested in right now). Let's assume that it is true that working upwards from neuroscience eventually
reaches computer science and, given that we already have a way to implement computer science, reduce the problem to this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4069"><img src="https://img.incoherency.co.uk/4069/thumb"></a></p>
<p>Much more tractable!</p>
<p>Now assume we have developed a candidate "software mind", that might have its own conscious internal experience. How would we find out? How would we convince others?
We can't just hook it up to a text chat and ask it, because it might say it's conscious <a href="https://en.wikipedia.org/wiki/LaMDA#Sentience_claims">even if it is not</a>.
We need to be able to <i>show</i> that it is truly conscious.</p>
<p>So before we start building minds in software, we ought to agree on a way to <i>classify</i> them.
Traditionally this is very difficult, because the only way to decide whether a person has consciousness is to
experience it for yourself. Since you can only access your own internal experience, the only person whose
consciousness you can be sure of is yourself.</p>
<p>Currently our best heuristic for determining whether something <i>else</i> is conscious is to check how much it behaves like a human.
Humans: as conscious as it gets. Apes: very conscious. Dogs: quite conscious. Plants: vegetative. Rocks: nothing going on, nobody home,
not at all conscious.</p>
<p>This works surprisingly well in ordinary daily life, but is not very effective at identifying a mind that isn't like a human. It would be like checking whether a plane can fly
by measuring how much it looks like a bird.</p>
<p>If we are creating minds in software, however, we have the advantage that we have <i>total access to all of the internal state
of the system, while it's running</i>. So what things would we look for in a hypothetical software mind to determine whether or not it's conscious?</p>
<p>I don't know. But maybe answering that would give us some pointers on how to construct one.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/classifying-minds.html</link>
   <guid>http://incoherency.co.uk/blog/stories/classifying-minds.html</guid>
   <pubDate>Tue, 25 Oct 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Alternative revolutions</title>
   <description><![CDATA[You can use the profile of an object that has rotational symmetry,
but revolve it around a different axis, to produce a different object that
has the same profile. It feels like there's a puzzle idea in there somewhere, but
I can't work out the best way to turn it into
an actual puzzle, so if you have any ideas please let me know.]]></description>
   <content:encoded><![CDATA[<p>You can use the profile of an object that has rotational symmetry,
but revolve it around a different axis, to produce a different object that
has the same profile. It feels like there's a puzzle idea in there somewhere, but
I can't work out the best way to turn it into
an actual puzzle, so if you have any ideas please let me know.</p>
<p>I suspect the kind of people who might be good at this puzzle are those who
do a lot of CAD and those who do a lot of lathe work, because they both
involve grappling with the equivalence between the 2d profile and the
3d revolved shape.</p>
<p><h2>Profiles</h2></p>
<p>Here's a rough profile of a chess pawn, and the shape you get by revolving it around the tall vertical edge:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4033"><img src="https://img.incoherency.co.uk/4033/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4034"><img src="https://img.incoherency.co.uk/4034/thumb"></a></p>
<p>The idea behind "alternative revolutions" is that we can revolve the <i>same</i> profile around a different edge
to get a different object:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4035"><img src="https://img.incoherency.co.uk/4035/thumb"></a></p>
<p>Hopefully you see that this has the same profile, but is a completely different shape.</p>
<p>We also have the option to make <i>negatives</i> by taking a negative of the profile:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4036"><img src="https://img.incoherency.co.uk/4036/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4038"><img src="https://img.incoherency.co.uk/4038/thumb"></a></p>
<p>This is the same profile, except now the right hand side, instead of the left hand side, is "inside" the shape.</p>
<p>And we can do the same with the horizontal axis instead of the vertical axis.
For some reason the 3D shape created by this profile is very confusing to look at, but it should make
sense if you keep remembering the profile that it's made out of.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4037"><img src="https://img.incoherency.co.uk/4037/thumb"></a></p>
<p>(This part would exactly mate with the first "alternative revolution" above).</p>
<p>And the same thing with the other horizontal edge:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4043"><img src="https://img.incoherency.co.uk/4043/thumb"></a></p>
<p>The mating part for which is:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4044"><img src="https://img.incoherency.co.uk/4044/thumb"></a></p>
<p>We can sweep around an axis that is spaced away from our profile, to leave a hole in the middle:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4039"><img src="https://img.incoherency.co.uk/4039/thumb"></a></p>
<p>And our profile can either face outwards (above) or inwards:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4040"><img src="https://img.incoherency.co.uk/4040/thumb"></a></p>
<p>And the same with the horizontal rotation axis:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4041"><img src="https://img.incoherency.co.uk/4041/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4042"><img src="https://img.incoherency.co.uk/4042/thumb"></a></p>
<p>And of course the same is also possible with the negative version of the profile, which among other
things lets us make a mating part for the standard chess pawn:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4048"><img src="https://img.incoherency.co.uk/4048/thumb"></a></p>
<p>We also have the option to tilt the rotation axis if we want to:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4045"><img src="https://img.incoherency.co.uk/4045/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/4046"><img src="https://img.incoherency.co.uk/4046/thumb"></a></p>
<p>This lets us smoothly interpolate between the version with the vertical rotation axis and the one with the horizontal rotation axis:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4047"><img src="https://img.incoherency.co.uk/4047/thumb"></a></p>
<p>With a bit more creative license, we could decide that we don't want the hollow cones that give the game away,
and we could easily cap off the top and bottom with flat surfaces.</p>
<p>(Sadly I can't think of a way to smoothly interpolate between the positive and negative version of the profile.)</p>
<p>So there are quite a lot of different shapes we can make, given just one profile, by having the option
to turn the profile negative, and varying the position and direction of the rotation axis.</p>
<p><h2>Puzzle ideas</h2></p>
<p><b>Identify common objects</b>: We give the player a bunch of objects that are made by revolving common object profiles
(some positive, some negative) in uncommon ways. The player has to figure out what common object each shape is based on,
and then... what? Concatenate the words to form a password? Just gain the satisfaction from having solved it?</p>
<p><b>Matching pairs</b>: We give the player a bunch of objects that are made out of contrived profiles (i.e. arbitrary shapes we
make up, not necessarily related to objects that the player would know). The player has to work out which of the objects
share profiles and pair them up. And then... there's a number on some of the objects and a letter on the others, and they have to
put the letters together in order of the numbers to make a password?</p>
<p><b>Odd one out</b>: We give the player a bunch of objects that can be made out of contrived profiles or common ones, and they
have to locate the only object that doesn't share a profile with any of the other objects (or, along similar lines,
they have to locate the only pair of objects that <i>do</i> share a profile).</p>
<p><b>Data encoding</b>: We can come up with a way to encode a small amount of data in the profile (as an existence proof: make a large
radius for a 1 bit and a small radius for a 0 bit, but more interesting stuff is possible) and the player gets the objects and
has to decode the data we've given them. Maybe in combination with "odd one out" or "matching pairs" to work out which pieces of
data are actually useful and in what order?</p>
<p>Normally I prefer (dis-)assembly puzzles, or something that acts like a box and you have to solve the puzzle to retrieve an
object, but I can't see a way to readily adapt the "alternative revolutions" to anything interesting. Probably the best option
is to just use it as a matching puzzle to encode a combination for a padlock in an escape room.</p>
<p>What better ideas do you have?
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/alternative-revolutions.html</link>
   <guid>http://incoherency.co.uk/blog/stories/alternative-revolutions.html</guid>
   <pubDate>Mon, 03 Oct 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Solving Protohackers with Fly.io</title>
   <description><![CDATA[This post walks you through hosting a Go solution for the
Protohackers Smoke
Test problem using Fly.io for free hosting.]]></description>
   <content:encoded><![CDATA[<p>This post walks you through hosting a Go solution for the
Protohackers <a href="https://protohackers.com/problem/0">Smoke
Test</a> problem using <a href="https://fly.io/">Fly.io</a> for free hosting.</p>
<p>Fly.io can host anything that can run in a Docker container, and you don't even need to write
your own Dockerfile because it automatically handles the most common languages and frameworks.
I wish the tooling were less verbose, it's as if it's got debug mode logging
permanently enabled. It is also quite slow. In principle we don't need any
more than building a tiny binary and <tt>scp</tt>ing it to a server, why does it take multiple minutes
to make a deployment?</p>
<p>Using Fly.io is slightly more trouble than using a normal VPS, so if you already have a VPS you will probably
find that easier.
Depending on your ISP, your router, and how comfortable you are with port forwarding, Fly.io could be either
more or less trouble than hosting your program at home. If you think hosting at home
sounds easy, then that is probably easier for you than Fly.io.</p>
<p>Let's assume that you don't want to pay for a VPS, and you can't host at home (maybe you are behind
<a href="https://en.wikipedia.org/wiki/Carrier-grade_NAT">CGNAT</a>). In that case Fly.io is your next best option!</p>
<p>Firstly, install Fly.io using the instructions on their website, which is currently:</p>
<p><pre><code>$ curl -L https://fly.io/install.sh | sh</code></pre></p>
<p>Follow its instructions to put its environment variables in your bashrc. Signup for Fly.io:</p>
<p><pre><code>$ fly auth signup</code></pre></p>
<p>This will try to open a page in your browser to let you either connect a GitHub account or sign up
with email.</p>
<p>Make a directory for your project and copy the Go example program from the
bottom of <a href="https://protohackers.com/help">the Protohackers
help page</a> into <tt>main.go</tt>.</p>
<p>Fly.io is supposed to be able to auto-detect a Go program and deploy it with just <tt>fly launch</tt>,
but I have found it doesn't auto-detect Go unless you have a <tt>go.mod</tt>. (You may have better luck with other
languages). To help it detect your Go program, run:</p>
<p><pre><code>$ go mod init example.com/foo
go: creating new go.mod: module example.com/foo</code></pre></p>
<p>Now we'll launch it on Fly.io. I accepted the defaults for everything.</p>
<p><pre><code>$ fly launch
Creating app in /home/jes/protofly
Scanning source code
Detected a Go app
Using the following build configuration:
	Builder: paketobuildpacks/builder:base
	Buildpacks: gcr.io/paketo-buildpacks/go
? App Name (leave blank to use an auto-generated name): 
Automatically selected personal organization: James Stanley
? Select region: lhr (London, United Kingdom)
Created app old-surf-8338 in organization personal
Wrote config file fly.toml
? Would you like to set up a Postgresql database now? No
? Would you like to deploy now? No
Your app is ready. Deploy with `flyctl deploy`</code></pre></p>
<p>The default Fly.io configuration is to run an HTTP proxy in front of your application,
but that's not what we want.</p>
<p>We need to edit the generated <tt>fly.toml</tt> file to make the <tt>[[services]]</tt>
section expose TCP directly rather than proxying with HTTP. There is more information
in their <a href="https://fly.io/docs/app-guides/udp-and-tcp/">UDP and TCP</a> documentation.</p>
<p>Clear out the <tt>[[services]]</tt> section of fly.toml and replace it with:</p>
<p><pre><code>[[services]]
  internal_port = 10000
  protocol = "tcp"
  
  [[services.ports]]
    port = 10000</code></pre></p>
<p>And deploy the application with <tt>fly deploy</tt>. This part is <i>extremely</i> verbose. It
would benefit from the <a href="http://www.linfo.org/rule_of_silence.html">Rule of Silence</a>. It
also takes quite a long time. You just have to wait.</p>
<p><pre><code>$ fly deploy
 
[... hundreds of lines redacted ...]
 
 1 desired, 1 placed, 1 healthy, 0 unhealthy
--&gt; v2 deployed successfully</code></pre></p>
<p>Once our application is "deployed successfully", it's up and listening on the public Internet.
Despite the hundreds of lines of output that we were shown, I think we actually
haven't been told what IP address our program is listening on. In my case the application
was called <tt>old-surf-8338</tt>, and we can find out what IP address it's listening on
by resolving <tt>old-surf-8338.fly.dev</tt>:</p>
<p><pre><code>$ host old-surf-8338.fly.dev
old-surf-8338.fly.dev has address 168.220.85.87
old-surf-8338.fly.dev has IPv6 address 2a09:8280:1::a:77b4</code></pre></p>
<p>So in my case we'll put <tt>168.220.85.87</tt> and port <tt>10000</tt> into the checker form:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4019"><img src="https://img.incoherency.co.uk/4019/thumb"></a></p>
<p>And the check should pass!</p>
<p><a class="img" href="https://img.incoherency.co.uk/4020"><img src="https://img.incoherency.co.uk/4020/thumb"></a></p>
<p>Great success indeed.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/protohackers-flyio.html</link>
   <guid>http://incoherency.co.uk/blog/stories/protohackers-flyio.html</guid>
   <pubDate>Sat, 24 Sep 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Nightdrive</title>
   <description><![CDATA[I've made a JavaScript simulation of driving at night time on the motorway.
It's hard to classify what it is. It's not a video, because it's generated dynamically.
It's not a game, because you just watch. It's not a screensaver, because it's
not the 90s. Maybe it's a "demo"?]]></description>
   <content:encoded><![CDATA[<p>I've made a JavaScript simulation of driving at night time on the motorway.
It's hard to classify what it <i>is</i>. It's not a video, because it's generated dynamically.
It's not a game, because you just watch. It's not a screensaver, because it's
not the 90s. Maybe it's a "demo"?</p>
<p>This is something I've been planning to make for years, but kept forgetting about. I
would only remember it when in the passenger seat of a car on the motorway at
night time, fascinated by the patterns of moving lights.</p>
<p>Here's a small embedded version, if your browser runs JavaScript:</p>
<p><canvas style="width:100%; height:300px" id="canvas"></canvas>
<script src="js/vector.js"></script>
<script src="js/scene.js"></script>
<script src="js/car.js"></script>
<script src="js/nightdrive.js"></script></p>
<p>For the full version (with music!) click here: <a href="https://incoherency.co.uk/nightdrive/">Nightdrive</a>.</p>
<p>Gina said it's a great way to find out how filthy your monitor is.</p>
<p>The entire scene is created purely by drawing circles on a HTML5 canvas. It actually works a lot
better than I expected. The biggest flaw is that the cars are totally transparent, so you can see lights
from distant cars even where they should be occluded by closer cars.</p>
<p><h2>Motorway simulation</h2></p>
<p>The core simulation is entirely 2-dimensional. The coordinate space looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4009"><img src="https://img.incoherency.co.uk/4009/thumb"></a></p>
<p>The motorway is always parallel to the <b><i>y</i></b>-axis.</p>
<p>Each car has a 2d position vector and a <b><i>y</i></b>-axis velocity (cars on our side having
positive velocity, and cars in the oncoming carriageway having negative velocity).</p>
<p><a href="https://github.com/jes/nightdrive/blob/c6490b6495e7098bd22da098430cf6c1a3bd3822/js/nightdrive.js#L17-L28">400 cars</a>
are positioned at 25 metre intervals, in random lanes, at initialisation time. They also have some <a href="https://github.com/jes/nightdrive/blob/c6490b6495e7098bd22da098430cf6c1a3bd3822/js/car.js#L14-L28">slight variation</a>
in the size, position, and colour of the lights. Cars in the left-most lane travel at a
constant simulated speed of about 40mph, in the middle lane at 70mph, and in the fast lane at 100mph.</p>
<p>When any car is "behind" the viewer (lower <b><i>y</i></b> coordinate), and with a lower velocity (will get further behind)
it is <a href="https://github.com/jes/nightdrive/blob/c6490b6495e7098bd22da098430cf6c1a3bd3822/js/car.js#L52-L56">wrapped forwards by 10km</a>. Similarly, when any car is 10km
"in front of" the viewer (higher <b><i>y</i></b> coordinate), and with a higher velocity (will get further ahead),
it is wrapped backwards by 10km.</p>
<p>That's enough to give the illusion of an infinite road with infinitely-many cars, travelling in both directions,
and at different speeds in different lanes.</p>
<p><h2>Projection</h2></p>
<p>A top-down view of a 2d world isn't the effect we're going for, so we need to first make our world coordinates 3-dimensional, and then project
them on to the 2-dimensional screen.</p>
<p>To make the coordinates 3-dimensional, I just add a "height" to every point in the 2d simulation. This works because all of the elements
I need are at constant heights above the ground: car headlights, cat's eyes, and street lights.</p>
<p>My projection into screen space is not necessarily mathematically sound. I just fiddled with it until it looked how I wanted.</p>
<p>To turn a point from world coordinates into screen coordinates we first subtract the observer's position, to
get a position <b><i>(x,y,z)</i></b> relative to the observer.</p>
<p>If the relative position vector has a negative <b><i>y</i></b> coordinate, then we know the object is behind the viewer and
therefore not visible, so we don't draw anything.</p>
<p>Otherwise, we find the distance to the object by taking the magnitude of the relative position vector:</p>
<p><b><i>dist = sqrt(x<sup>2</sup> + y<sup>2</sup> + z<sup>2</sup>)</i></b></p>
<p>Then our coordinates in screen space are:</p>
<p><b><i>x<sub>screen</sub> = x<sub>centre</sub> + k * x / dist<br>
y<sub>screen</sub> = y<sub>centre</sub> - k * z / dist</i></b></p>
<p>Where <b><i>k</i></b> is a scale factor that sets the size on the screen, and <b><i>(x<sub>centre</sub>, y<sub>centre</sub>)</i></b> is
the centre of the screen.</p>
<p>(We need to subtract for <b><i>y<sub>screen</sub></i></b> because in screen space positive <b><i>y</i></b> is down,
but in our world space positive <b><i>z</i></b> is up).</p>
<p>I found it actually worked better if I omitted the <b><i>x</i></b> offset from the
distance calculation (so just <b><i>sqrt(y<sup>2</sup> + z<sup>2</sup>)</i></b>), otherwise objects near the edge of the
field of view were weirdly distorted. But I wouldn't suggest doing that in the general case.</p>
<p>You can look at the actual <a href="https://github.com/jes/nightdrive/blob/c6490b6495e7098bd22da098430cf6c1a3bd3822/js/scene.js#L49-L75">projection
function</a> I used if you like.</p>
<p><h2>Terrain</h2></p>
<p>To make the road a bit more interesting we can add some hills. I wrote a function adding up some arbitrary sine waves
to make something that seemed reasonable:</p>
<p><pre><code>function terrain(y) {
    return 10*Math.sin(y/1000) + 5*Math.cos(y/527) + 2*Math.sin(y/219);
}</code></pre></p>
<p>This takes a <b><i>y</i></b> coordinate in road space, and returns the height of the road at that point. This is then
added to all <b><i>z</i></b> coordinates by the projection function.</p>
<p>Looking at the road from the side, the terrain it generates looks something like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4010"><img src="https://img.incoherency.co.uk/4010/thumb"></a></p>
<p>(<b><i>x</i></b> on the graph is <b><i>y</i></b> in world-space, <b><i>y</i></b> on the graph is
<b><i>z</i></b> in world-space, both in metres).</p>
<p><h2>Road occlusion</h2></p>
<p>At this point we have quite a glaring issue: we can see through the ground!</p>
<p><a class="img" href="https://img.incoherency.co.uk/4011"><img src="https://img.incoherency.co.uk/4011/thumb"></a></p>
<p>Everything the other side of the crest of the hill should be occluded by the hill, but since all we're doing is projecting
positions of lights, nothing can ever get occluded by anything.</p>
<p>A point <b><i>P</i></b> is occluded by the road if there is any position, between the viewer and <b><i>P</i></b>, that has a
screen-projected road height "higher" (smaller value) than the screen-projected <b><i>y</i></b> coordinate of <b><i>P</i></b>. Because that means if we were to actually draw the road, it would get drawn over the top
of <b><i>P</i></b>.</p>
<p>I sorted
all rendered lights by distance from the viewer (closest first), and walked along the list, keeping track of the highest screen-space
road height so far
encountered, and occluding any points that fall "below" that height. That means we'll occlude any points that fall behind
the road position at any closer position <i>that has a light on it</i>. This is good enough, because we always have
frequent-enough sampling of the
terrain function due to the density of cars and street lights.</p>
<p>You can look at <a href="https://github.com/jes/nightdrive/blob/c6490b6495e7098bd22da098430cf6c1a3bd3822/js/scene.js#L24-L48">the implementation</a> if you like.</p>
<p>Come to think of it, I expect there might be an analytical solution to determining whether any given
point should be occluded by the road.
Maybe that would be better! We just need to find out whether the straight line
passing through the camera and <b><i>P</i></b> intersects the road at any point between the camera and <b><i>P</i></b>: if it does then <b><i>P</i></b> is occluded by the road.</p>
<p><a class="img" href="https://img.incoherency.co.uk/4012"><img src="https://img.incoherency.co.uk/4012/thumb"></a></p>
<p><h2>Music</h2></p>
<p>The background music is from <a href="https://www.youtube.com/watch?v=4s--btQafWs">this video</a>
which describes it as "Royalty Free".</p>
<p>I've been told that the audio quality on Nightdrive is bad. I did this on purpose to reduce the size of
the mp3, and it doesn't sound bad to me. If you think it sounds bad then you should mute Nightdrive
and play that YouTube video in a different tab.</p>
<p><h2>More</h2></p>
<p>There are a few more things that I think would be fun to do:</p>
<p><b>Bends</b>: Instead of having a perfectly-straight road, it would be good to add some bends, so the patterns of lights would curve off into the distance, something like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4013"><img src="https://img.incoherency.co.uk/4013/thumb"></a><br>
<small>(From <a href="https://www.flickr.com/photos/jonnywalker/5790211425">jonnywalker on flickr</a>)</small></p>
<p><b>Street light occlusion</b>: Street lights aren't just magical floating orbs, they're held up by metal
poles. When something passes behind the metal pole, it is momentarily invisible. This would not be
too hard to do in Nightdrive. We'd just use a similar process to the "road occlusion" to hide lights that
are hidden by the poles.</p>
<p><b>Car occlusion</b>: Cars also are not just magical floating orbs, they have volume and are opaque. This would
be slightly harder than street light occlusion. Probably a first pass would be to render a black
cuboid behind each car's lights, so that the cuboid blocks out anything that would be blocked by the car.
This is inconvenient because currently we can only render circles.</p>
<p><b>Speed variation</b>: Not every car in the same lane drives at exactly the same speed. Sometimes you
catch up to the car in front, or the car behind catches up to you. Adding speed variation is easy,
but comes with the problem that cars end up driving through each other, which for some reason feels unrealistic.
This brings us on to...</p>
<p><b>Lane changes</b>: When a car catches up to the car in front, it should indicate right and
move over to overtake. When it has passed and there's a space on the left it should indicate left and move back over. We
could give each car a sort of "personality" which tells it how close it can get to other cars, how long it
should indicate for before changing lanes, etc.</p>
<p><b>Rain shader</b>: A rain effect <i>might</i> be too much trouble to do with just a canvas. Maybe it would need
WebGL. But I would like to apply some sort of rain shader to the rendered image to give the effect of
driving at night time. We can imagine having a collection of "droplets" on the "windscreen" which refract the
light passing through them (dots that distort the pixels underneath). Periodically we could sweep a windscreen wiper
across the field of view to clear the dots, and we can randomly add dots at some rate based on how heavily it's
raining.</p>
<p><b>Game</b>: Finally, I wonder how we could turn this into some sort of game? I'm especially <i>not</i>
looking to make a driving game. I still want the car to basically drive itself. What game can we make
where the premise is that you're a passenger on the motorway at night time?
It shouldn't be
a particularly taxing game, I think the main experience should still be that you're just enjoying
watching the lights, but it would be cool if there was some interactivity and some sort of goal.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/nightdrive.html</link>
   <guid>http://incoherency.co.uk/blog/stories/nightdrive.html</guid>
   <pubDate>Fri, 16 Sep 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Protohackers problem 2 retrospective</title>
   <description><![CDATA[I released Protohackers problem 2 on Thursday
evening. The problem asks you to implement a server that stores timestamped price data and lets
clients query the mean price over custom time ranges. (This post contains potential spoilers for
the problem; if you have not solved it yet, and you would like to solve it, then to avoid disappointment you should not read this until after you've solved it!).]]></description>
   <content:encoded><![CDATA[<p>I released <a href="https://protohackers.com/problem/2">Protohackers problem 2</a> on Thursday
evening. The problem asks you to implement a server that stores timestamped price data and lets
clients query the mean price over custom time ranges. (This post contains potential spoilers for
the problem; if you have not solved it yet, and you would like to solve it, then to avoid disappointment you should not read this until after you've solved it!).</p>
<p>So far, <b>499</b> people have signed up for the site (+437 since <a href="https://incoherency.co.uk/blog/stories/protohackers-problem-1.html">last time</a>). <a href="https://protohackers.com/leaderboard/0">199</a> have solved the test problem (+170) and <a href="https://protohackers.com/leaderboard/2">76</a> have solved <a href="https://protohackers.com/problem/2">the latest problem</a> (+62).</p>
<p>The reason behind the big increase in users is that there was a <a href="https://news.ycombinator.com/item?id=32767263">thread
about Protohackers</a> on the HN front page for a little while.</p>
<p><h2>The problem statement</h2></p>
<p>So far there has only been one point of confusion highlighted in the problem statement (a big improvement
over last time!).</p>
<p>The problem statement said:</p>
<p><blockquote>Because each client's data represents a different
asset, each client can only query the data supplied by itself.</blockquote></p>
<p>To my mind it was obvious that each <i>connection</i>
was a separate client, but some people interpreted it to mean that only unique client <i>IP addresses</i> are separate clients,
and that every connection from the same IP address counts as the same client.</p>
<p>I've updated the problem text to say:</p>
<p><blockquote>Each connection from a client is a separate session. Each session's data represents a different asset, so each session can only query the data supplied by itself.</blockquote></p>
<p>Ideally the problem statement would never get changed for any reason, so that every user always sees the same text.
However, where the problem
statement is confusing, I consider that a bug, and bugs should be fixed.</p>
<p>Someone pointed out in the Discord chat that it is very weird for clients to be "analysing historical price data", but
permanently lose access to it as soon as they disconnect. It is weird, I agree. The intention for this
problem was that you need to persist state across multiple requests (compared to the previous problem
where you didn't have to persist any state), but you do <i>not</i>
have to share state between multiple clients.</p>
<p><h2>Email deliverability</h2></p>
<p>A handful of people have not been receiving the signup/login emails. Two American universities are bouncing the mails
with a message about poor domain reputation. I have emailed <tt>postmaster@</tt> their domains to ask to get unblocked.</p>
<p>Two (would-be) users have email on their own domains hosted by Fastmail, which seems to be silently blackholing the mails
with <i>no</i> bounce message. I've opened a support ticket with Fastmail.</p>
<p>So I don't know if I will have to add some alternative non-email-based login flow, or whether the problem will get solved
on its own over time as a.) I complain to people who are blocking the emails, and b.) the domain reputation improves as
it ages.</p>
<p><h2>Upcoming features</h2></p>
<p><h3>Overall leaderboard</h3></p>
<p>I still haven't done the overall leaderboard. The current plan is that if <i>N</i> people have ever
successfully solved any problem, then your rank for a problem you haven't solved yet will be <i>N+1</i>, and the
overall leaderboard will be ranked by your summed rank, ascending.</p>
<p>(So if there are 3 problems, and you got 1st place on all 3, your score is 3. If you got 2nd place on all 3, your
score is 6, which is higher than 3, which is a worse overall ranking).</p>
<p>I don't like the fact that in cases where people have not solved all problems, their leaderboard positions can be changed
even if they don't do anything (just because new people solve some problems, which increases <i>N</i>),
but I think it is better than any alternative I can think of, and in particular it <i>is</i> stable for those users
that have solved all problems, <i>and</i> it means you always get an improvement in your overall score by solving
a new problem.</p>
<p>I am keen not to create any overall leaderboard until the logic is definitely settled, because I don't want to give
someone 1st place on the leaderboard and then change my mind and hand it to someone else!</p>
<p><h3>IPv6</h3></p>
<p>Several people have asked about IPv6, including one person who has a VPS that apparently <i>only</i> has IPv6 connectivity.
So I plan to look at adding IPv6 support. I am wary that this will double the surface area of possible
connectivity issues, but I think it is worth doing.</p>
<p>The most important part is that the checker can access people's servers using IPv6, but it would also be nice if the
web site was available over IPv6.</p>
<p><h2>Dashboard</h2></p>
<p>I have an <a href="https://shop.pimoroni.com/products/inky-what">InkyWHAT</a> screen hanging from a shelf next to my
desk with a 3d-printed bracket:</p>
<p><a class="img" href="https://img.incoherency.co.uk/4006"><img src="https://img.incoherency.co.uk/4006/thumb"></a></p>
<p>It shows the total number of users, problem attempts, and problem solutions, as well as information about the most recent
accepted solution, the current time, and the server's CPU load.</p>
<p>Mainly it just saves me from having to manually look this stuff up in the database. It gets its data from a special
(authenticated) API endpoint.</p>
<p>If you have an InkyWHAT and you don't like how it totally fades to black every time you update the screen,
you should use the <a href="https://github.com/evilsocket/pwnagotchi/blob/f0c5ad4b74a0461757f0bf5984a36ca6754b6f77/pwnagotchi/ui/inkyphat/inkyfast.py">InkyFast wrapper from pwnagotchi</a> - it uses an alternative lookup table for the display
driver so that it updates more quickly. It can leave a tiny amount of ghosting, but it's a big improvement over
the whole display fading to black every 10 seconds.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/protohackers-problem-2.html</link>
   <guid>http://incoherency.co.uk/blog/stories/protohackers-problem-2.html</guid>
   <pubDate>Sun, 11 Sep 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How small can you make text with a drag engraver?</title>
   <description><![CDATA[A drag engraver is a very sharp spring-loaded tool that you can hold in a CNC
spindle and drag over a piece of metal to engrave fine lines.]]></description>
   <content:encoded><![CDATA[<p>A drag engraver is a very sharp spring-loaded tool that you can hold in a CNC
spindle and drag over a piece of metal to engrave fine lines.</p>
<p>Mine looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3987"><img src="https://img.incoherency.co.uk/3987/thumb"></a></p>
<p>It has a piece of diamond at the tip.</p>
<p>You don't turn the spindle motor on, you're just using the spindle to hold the tool.
Being spring-loaded means it conforms to slightly out-of-level surfaces while
maintaining almost constant pressure.</p>
<p><h2>Ring</h2></p>
<p>Yesterday I used the drag engraver with my <a href="https://incoherency.co.uk/blog/stories/cnc-rotary-axis.html">weird
rotary axis</a> to engrave a commemorative ring I made for an upcoming
special occasion. The quality of the engraving was <i>much</i> better than I expected,
so I want to do more of it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3997"><img src="https://img.incoherency.co.uk/3997/thumb"></a></p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/coAPufhvUgU" frameborder="0" allow="allowfullscreen" allowfullscreen></iframe></p>
<p>I want to make a ring that has a huge amount of tiny text
engraved on it, but first I need to know how small I can make the text before it becomes illegible.</p>
<p><h2>Test card</h2></p>
<p>I drew up a little test card in Inkscape:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3985"><img src="https://img.incoherency.co.uk/3985/thumb"></a></p>
<p>This has text from 4mm down to 0.5mm in 0.5mm steps, and then down to 0.2mm in 0.1mm
steps.</p>
<p>(Incidentally, I find Inkscape very annoying to use for engraving toolpaths,
because Inkscape includes the thickness of a line in its dimensions. This means when
you resize a piece of text to be 4mm tall, you actually end up slightly under-size,
because the thickness of the line is included in the "4mm" measurement).</p>
<p>This text is generated with the "Hershey Text" plugin using the "Sans 1-stroke"
font.</p>
<p>I engraved it on an offcut of 1mm aluminium sheet with the CNC machine:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3988"><img src="https://img.incoherency.co.uk/3988/thumb"></a></p>
<p>(It turns out it's quite hard to take a picture of a very shiny piece of metal - the
text is much easier to read in-person).</p>
<p>The aluminium sheet is a much softer material than the ring.
I don't actually know what metal the
ring is made of, it's some surprisingly-hard type of brass or bronze. It was
a small piece of scrap left in my garage by the previous owner of the house.</p>
<p>Due to the softness of the aluminium, the engraved lines on my test piece are quite a bit
deeper than on the ring, which
tends to make the smaller text harder to read because adjacent lines blend into
each other.</p>
<p><h2>Conclusion</h2></p>
<p>All sizes from <b>1mm and up</b> are legible.</p>
<p>I reckon <b>0.5mm</b> is legible if you squint. 0.4mm and 0.3mm are legible without
magnification only if
you already know what the text says. I don't consider 0.2mm legible even though I
know what it says.</p>
<p>Given that the lines we'd get on the ring will be thinner, I think it
is safe to go below 1mm. Possibly I'd suggest <b>0.6mm</b> just to be on the safe side.</p>
<p><h2>Under the microscope</h2></p>
<p>Just for fun I took some pictures with the USB microscope:</p>
<p>0.2mm:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3992"><img src="https://img.incoherency.co.uk/3992/thumb"></a></p>
<p>0.3mm:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3993"><img src="https://img.incoherency.co.uk/3993/thumb"></a></p>
<p>0.4mm and 0.5mm:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3994"><img src="https://img.incoherency.co.uk/3994/thumb"></a></p>
<p>0.4mm and 0.5mm again:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3995"><img src="https://img.incoherency.co.uk/3995/thumb"></a></p>
<p><h2>Drag-engraved PCBs</h2></p>
<p>I have made a circuit board with <a href="https://incoherency.co.uk/blog/stories/pcb-milling-2.html">isolation routing</a> before, but I found it very difficult. In total I have had maybe 7 attempts at
making PCBs with isolation routing, with only the 1 success.</p>
<p>The major problems I had were:</p>
<p><ul>
<li>the surface is never truly flat, which means the cut depth is different in
different places; it might cut so deep that it obliterates your trace in one area, while it's not even isolating the traces in another</li>
<li>the width of the cut is too big because the tiny v-bit tools are rarely concentric enough</li>
</ul></p>
<p>You can solve the flatness problem by probing the surface and correcting for its shape, but I haven't established
a good workflow for that. I'm <a href="https://whynot.fail/factory/making-pcbs-at-home-milling-the-first-layer/">told</a> that <a href="https://github.com/vlachoudis/bCNC/">bCNC</a> is the tool to use, but haven't got around to trying it yet.</p>
<p>I have quite a lot of fine-tipped v-engraving bits, but I have broken the one I used to
create the successful PCB. All of the others, despite having very thin and precise tips,
are not concentric, which means the tip spins around in a big circle and routes a slot
much bigger than the size of the tool. Buying more expensive tools would probably help,
but I break them so frequently that I'm not prepared to pour more money into them.</p>
<p>Anyway, my big idea here is to try <b>using the drag engraver to do the isolation routing</b>!
It kills both birds with one stone: it automatically corrects for an out-of-level surface
because it's spring-loaded,
and it gives you an extremely thin cut because it's not spinning.</p>
<p>As long as the drag engraver can provide enough pressure to cut all the way through the
copper I don't see what could go wrong. So I plan to try this tomorrow.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/drag-engraver-text.html</link>
   <guid>http://incoherency.co.uk/blog/stories/drag-engraver-text.html</guid>
   <pubDate>Mon, 05 Sep 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The future of virtual reality</title>
   <description><![CDATA[I know very little about artificial intelligence. Mainly I just like to argue
that machines can be sentient, because I don't see the difference between a computer
and a brain. But I think the new prompt-driven
AI stuff is incredibly powerful, and I don't think we're that many steps away from
being able to create fully-immersive virtual worlds that can be summoned at will
from free-form English-language prompts.]]></description>
   <content:encoded><![CDATA[<p>I know very little about artificial intelligence. Mainly I just like to argue
that machines can be sentient, because I don't see the difference between a computer
and a brain. But I think the new prompt-driven
AI stuff is incredibly powerful, and I don't think we're that many steps away from
being able to create fully-immersive virtual worlds that can be summoned at will
from free-form English-language prompts.</p>
<p>GPT-3 takes a prompt and creates more text. Stable Diffusion takes
a prompt and creates an image. Copilot takes a prompt and creates source code.</p>
<p>We only need to imagine a <i>very small</i> number of new technologies, along similar lines,
in order to create 3-dimensional worlds, and interaction logic, from simple
text prompts.</p>
<p>Just imagine an extra layer on top of Stable Diffusion that takes the same kinds of prompts,
but it generates you a 3d world instead of a 2d image.</p>
<p>Imagine an extra layer on top of Copilot that generates an entire application rather than
just small functions, and prime it to create common video game interaction patterns
rather than leetcode solutions.</p>
<p>Maybe it would require very detailed prompts? OK, let's imagine using something
like GPT-3 to turn a single coarse-grained "world prompt" into the fine-grained prompts for the underlying
layers.</p>
<p>Now put on your VR headset. Connect to your friend who lives on the other side of the world.
Give it a world prompt:</p>
<p><blockquote>I'm a cop, my friend is a robber. I am
chasing him through the streets of Chicago at night time. In the rain. If I catch him within 15 minutes I
win, otherwise he wins. Also we each have a radar on our wrist that tells us the direction
to the other player. Go!</blockquote></p>
<p>The VR system comes with a built-in concept of what a 3d world is, how your motions in the real
world control a character in the virtual world, how to link up multiple players into a single world
over the Internet, etc.</p>
<p>Copilot++ has created the tiny bit of interaction logic to set a 15-minute timer, work out
whether you've "caught" the robber, and implemented the standard
"radar arrow on the wrist" pattern that is probably just a Unity++ plugin.</p>
<p>StableDiffusion++ has created the 3d world (both geometry and textures) and continuously paints in
new areas of the world as they come into view.</p>
<p>So now you've got a reasonably photorealistic, fully-interactive, immersive 3d world, created
to your specification, and a game to play against your friend, also created to your specification.
You're almost <i>actually</i> a cop
chasing a robber through the streets of Chicago at night time. In the rain.</p>
<p>And you can set
the prompt to whatever you want! Literally anything you want. Literally <i>everything</i> is possible.
It's like AI Dungeon on steroids.</p>
<p>When you ask it for a world, your experience would be exactly like
doing the thing for real, except maybe sometimes the people have extra limbs and none of
the text makes sense.</p>
<p>Why can't this exist? I think this can exist. I think the only question is how long it's
going to take.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/future-vr.html</link>
   <guid>http://incoherency.co.uk/blog/stories/future-vr.html</guid>
   <pubDate>Sat, 03 Sep 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Protohackers problem 1 retrospective</title>
   <description><![CDATA[I released Protohackers problem 1 on Thursday evening.
The problem asks you to implement a server that accepts JSON-encoded requests, tests numbers for primality,
and gives JSON-encoded responses. (This post contains spoilers for the problem; if you have not solved it
yet, and you would like to solve it, then to avoid disappointment you should not read this until after you've solved it!).]]></description>
   <content:encoded><![CDATA[<p>I released <a href="https://protohackers.com/problem/1">Protohackers problem 1</a> on Thursday evening.
The problem asks you to implement a server that accepts JSON-encoded requests, tests numbers for primality,
and gives JSON-encoded responses. (This post contains spoilers for the problem; if you have not solved it
yet, and you would like to solve it, then to avoid disappointment you should not read this until after you've solved it!).</p>
<p>So far, <b>62</b> people have signed up for the site (much more than I expected!), of whom <a href="https://protohackers.com/leaderboard/0">29</a> have successfully solved the <a href="https://protohackers.com/problem/0">test problem</a>.
<b>19</b> have attempted the <a href="https://protohackers.com/problem/1">first "real" problem</a>, with <a href="https://protohackers.com/leaderboard/1">14</a> having solved it successfully.
It's not clear whether the other 5 have been discouraged and walked away for good, or whether they'll be
back for another go.</p>
<p>Amusingly, first and second place on the leaderboard were separated by only 2 seconds!</p>
<p><a class="img" href="https://img.incoherency.co.uk/3983"><img src="https://img.incoherency.co.uk/3983/thumb"></a></p>
<p>I don't know if these two were communicating or not, but they were submitting different IP addresses, so I
assume they were not working together.</p>
<p><h2>Discord server</h2></p>
<p>Two people emailed me and asked about setting up a Discord server for people to join, so now there is one.
If you want to join, you can click: <a href="https://discord.gg/RqqmGePnWU">https://discord.gg/RqqmGePnWU</a>.</p>
<p><h2>The problem statement</h2></p>
<p>There were a few issues with the problem statement that I hope not to repeat in future problems.</p>
<p>The initial release of the problem statement didn't explicitly allow clients to make multiple requests
over one connection! That's bad, because it means depending on your preconceptions of how the
protocol is likely to work, you might assume that the client makes a single request, receives
a single response, and then disconnects. Multiple people implemented servers that assumed only a single request
per session was allowed. I have clarified this now.</p>
<p>The problem statement initially stated that the <tt>"number"</tt> field of the request object needed to contain
a <i>number</i> in order to be considered well-formed, but some people assumed this meant it needed
to contain an <i>integer</i>. While I maintain that a thorough and pedantic reading of the
problem statement would lead to the correct interpretation, that shouldn't be the standard: a casual reading by
a competent programmer should be enough to arrive at a correct understanding, especially when you consider that
many users may not speak English as a first language.</p>
<p>Eric Wastl (creator of Advent of Code) says something like:</p>
<p><blockquote>for each sentence in the problem statement, there is at least one user who reads everything <i>except</i> that sentence.</blockquote></p>
<p>The intention was that non-integers are still accepted as well-formed
requests, but that they are not prime (because only integers can be prime).
But this is really just a distraction from the core purpose of Protohackers,
which is to write programs that implement network protocols. Annonyingly-pedantic input validation is not
the goal. I've updated the problem statement to be more explicit
about the intent, and will try to avoid doing this sort of thing again.</p>
<p>One person was confused about exactly what I meant by a "newline character":</p>
<p><blockquote>Each request is a single JSON object followed by a newline character ('\n', or ASCII 10)</blockquote></p>
<p>They were outputting the literal string <tt>\n</tt> (i.e. a backslash followed by an "n"). I'm not really sure what to
do about that. Maybe I should hyperlink "newline character" to the <a href="https://en.wikipedia.org/wiki/Newline">Newline</a>
Wikipedia page?</p>
<p><h2>The checker</h2></p>
<p>A weird quirk of the protocol
is that the correct behaviour, in response to a malformed request, is to send a <i>malformed response</i>, rather than
some sort of standardised error response. I just thought this had an amusing symmetry.</p>
<p>Unfortunately, my checker was not correctly interpreting all malformed responses. It only considered invalid JSON
to be a malformed response, even though the problem statement said that a response was "malformed" even if it was valid
JSON, but had fields missing, or invalid values in the fields. I had failed at making a sufficiently-pedantic
interpretation of the problem statement in exactly the same way I was trying to test the <i>users'</i> interpretations
of the problem statement. An amusing symmetry indeed. Hoist by my own petard! (This is fixed now).</p>
<p>One of the test cases is a really long number (something like 63 digits long). These are selected at random and
almost always have low factors, so it shouldn't be too much of a problem to test them for primality. But sometimes
bigints are too inconvenient. What then? At least one person noticed that the only test case that had a number larger
than 64 bits also had a spurious extra field in the JSON (<tt>"bignumber":true</tt>), and he simply tested for this
field, and returned a "non-prime" response without even checking the number! Lol.</p>
<p><h2>Logo</h2></p>
<p>I paid a man on Fiverr &pound;15 to design a logo for Protohackers. The brief was something like "I want a logo
that will fit with the existing colour scheme, and convey programming and networking".
He came up with these three:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3981"><img src="https://img.incoherency.co.uk/3981/thumb"></a></p>
<p>I can kind of see what he's trying to do with angle brackets on the first one, although it seems a bit more "HTML"
than "HTTP". The second one clearly conveys the Internet, and connectivity, but I can't help seeing it as a cartoon
snail. I'm going with the third option, but resized and rearranged to look a bit more subtle on the page:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3982"><img src="https://img.incoherency.co.uk/3982/thumb"></a></p>
<p><h2>Still to solve</h2></p>
<p>I haven't yet worked out whether/how to create an "overall" leaderboard that combines the scores from the individual
problem leaderboards. The Advent of Code solution is to cap the daily leaderboard at 100 places, assign 100
points for 1st place, 99 for 2nd place, etc. down to 1 point for 100th place, and add up all the points to form the overall leaderboard.</p>
<p>I'd like to find a solution that includes more than the top 100 places (admittedly, a leaderboard with more than 100
names on it is still a fair way off!). One option is to add up the leaderboard <i>position</i> for each problem's
leaderboard, and then the lowest sum is the highest ranked on the overall leaderboard, but this has the drawback that
people who haven't completed all of the problems can't be ranked on the overall leaderboard.</p>
<p>So I'm looking for a ranking solution with the following properties:</p>
<p><ul>
    <li>completeness: rank everybody who has ever completed any problem</li>
    <li>fairness: if Alice and Bob have completed the same subset of problems, and Alice beat Bob on every problem, then she should be ahead of Bob overall</li>
    <li>stability: if Alice is ahead of Bob overall, and then Charlie comes along and submits a solution to a problem that both Alice and Bob have already solved, Alice and Bob's rankings are undisturbed</li>
</ul></p>
<p>The Advent of Code global leaderboard satisfies fairness and stability, but not completeness.</p>
<p>Advent of Code also has <i>private leaderboards</i>, where you score points based not on 1..100, but on 1..N where N is the number
of people in the private leaderboard. This satisfies completeness and fairness, but not stability, because
adding a new person to the group can change the relative positions of people who were already in the group! (Because every submitted
problem is now worth 1 more point: someone who got a high score on 1 problem only gets 1 more point, but someone who got low scores
on M problems gets M more points).</p>
<p>It may be the case that there is not any possible ranking algorithm that satisfies all 3 criteria. I'm pretty sure this is
not a new problem, so I probably just need to do some reading.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/protohackers-problem-1.html</link>
   <guid>http://incoherency.co.uk/blog/stories/protohackers-problem-1.html</guid>
   <pubDate>Sat, 27 Aug 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Protohackers: a new server programming challenge</title>
   <description><![CDATA[For the last couple of weeks I've been working on Protohackers, which is
a programming challenge where you have to implement a server for a network protocol,
and your server is automatically checked to see if it works properly. It's a bit like Advent of Code, but for networking instead of algorithms.]]></description>
   <content:encoded><![CDATA[<p>For the last couple of weeks I've been working on <a href="https://protohackers.com/">Protohackers</a>, which is
a programming challenge where you have to implement a server for a network protocol,
and your server is automatically checked to see if it works properly. It's a bit like <a href="https://adventofcode.com/">Advent of Code</a>, but for networking instead of algorithms.</p>
<p>Currently only the "Smoke Test" problem is available.
This problem is intended to make sure you have your networking setup sorted out, so that you can deploy a program that accepts connections and receives and sends data. </p>
<p>If you are having trouble getting the Smoke Test to pass please ask for help! I want to see you succeed. I expect the most likely source of frustration is firewall configuration, but if you are just not familiar with your favourite language's networking libraries, I'll lend a hand with that too.</p>
<p>The next problem will be released on Thursday at 17:00 UTC (18:00 in the UK) and my plan from then is to release a new one every ~2 weeks, but this could change based on user feedback.</p>
<p>Please take a look, tell your friends, and have a go at the smoke test.</p>
<p>Most importantly: if you think this is your kind of thing, tell me what you think about it, and what you would like to see changed. The project is currently in a larval stage, and feedback given at this time will have an outsized impact on the direction of future growth.</p>
<p>The link again is: <a href="https://protohackers.com/">https://protohackers.com/</a>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/protohackers.html</link>
   <guid>http://incoherency.co.uk/blog/stories/protohackers.html</guid>
   <pubDate>Tue, 23 Aug 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>A SLANG interpreter for SCAMP</title>
   <description><![CDATA[I made the interpreter by ripping the parser out of the compiler, making it produce an AST instead of assembly code,
and writing a recursive evaluator for the AST. It was way less work than writing
the Lisp interpreter, and it runs programs about 100x faster
than the Lisp interpreter.]]></description>
   <content:encoded><![CDATA[<p>I made the interpreter by ripping the parser out of the compiler, making it produce an AST instead of assembly code,
and writing a recursive evaluator for the AST. It was <i>way</i> less work than writing
the <a href="https://incoherency.co.uk/blog/stories/scamp-lisp.html">Lisp interpreter</a>, and it runs programs about 100x faster
than the Lisp interpreter.</p>
<p>I don't know why it didn't occur to me to write a SLANG interpreter sooner. Possibly I thought it would
be too much trouble, and only after I wrote the Lisp interpreter did I realise that it would not.
There's also the weirdness that SLANG code does not have automatic memory management, and I don't
know if I've ever seen an interpreted language that requires manual memory management (maybe FORTH, if you squint?).
SLANG just doesn't seem a natural fit for being interpreted.</p>
<p>But it turns out that if you don't have to bother with a garbage collector, and you don't care if the
computer crashes when the stack overflows, then writing the interpreter is quite straightforward. And these
arguably aren't even <i>defects</i> of the interpreter, because the compiled language works exactly
the same way. It's up to the programmer to make sure the program is not going to leak memory or run out of
stack space.</p>
<p>The <a href="https://github.com/jes/scamp-cpu/blob/master/sys/slangi.sl">source code</a> is currently slightly longer than that of the compiler:</p>
<p><pre><code>$ wc -l slangc.sl slangi.sl
 1230 slangc.sl
 1293 slangi.sl</code></pre></p>
<p>But this is only because I have reimplemented some of the more important parts in assembly language. Originally
it worked out slightly shorter than the compiler.</p>
<p>If you like, you can watch a video of <a href="https://www.youtube.com/watch?v=74K00OIcAWA">me using the
interpreter to solve Advent of Code 2018 day 4</a>.</p>
<p><h2>Usage</h2></p>
<p>The interpreter is available in the <a href="https://incoherency.co.uk/scamp/">online emulator</a>, just run
your program with <tt>slangi foo.sl</tt>, for example:</p>
<p><pre><code>$ cat foo.sl
printf("Hello, world!\n", 0);
$ slangi foo.sl
Hello, world!</code></pre></p>
<p>It overrides the <tt>cmdargs()</tt> system call so that arguments passed on the command line
(e.g. <tt>slangi foo.sl arg1 arg2 arg3</tt>) come out the same way they would do in the
equivalent compiled program.</p>
<p><h2>AST representation</h2></p>
<p>Each node of the AST is a pointer to an object whose first element is a pointer to the function that
evaluates the object. For example, you could create a node that returns a constant value like:</p>
<p><pre><code>var EvalConstNode = func(node) {
    return node[1];
};
 
var ConstNode = func(val) {
    var node = malloc(2);
    node[0] = EvalConstNode;
    node[1] = val;
    return node;
};
</code></pre></p>
<p>The objects are then evaluated with a helper function called <tt>eval</tt>:</p>
<p><pre><code>var eval = func(node) {
    var f = node[0];
    return f(node);
};</code></pre></p>
<p>Hopefully you can see that <tt>eval(ConstNode(42))</tt> will return 42.</p>
<p>We can easily make a node for <tt>if (<i>cond</i>) <i>thenblock</i> else <i>elseblock</i></tt> that tests its condition, evaluates its "then" block if the condition
is true, and evaluates its "else" block (if any) otherwise:</p>
<p><pre><code>var EvalConditionalNode = func(node) {
    var cond = node[1];
    var thenblock = node[2];
    var elseblock = node[3];
 
    if (eval(cond))
        eval(thenblock)
    else if (elseblock)
        eval(elseblock);
};
 
var ConditionalNode = func(cond, thenblock, elseblock) {
    var node = malloc(4);
    node[0] = EvalConditionalNode;
    node[1] = cond;
    node[2] = thenblock;
    node[3] = elseblock;
    return node;
};</code></pre></p>
<p>Composition of these different node objects gives us an object tree that represents the program structure, and
calling <tt>eval()</tt> on the root node results in evaluation of the entire program.</p>
<p><h2>Calling convention</h2></p>
<p>Calling convention on SCAMP is that the function arguments are pushed onto the stack
and the return address is passed in the <tt>r254</tt> pseudoregister (i.e. 0xfffe).</p>
<p><small>(Why isn't the return address
also passed on the stack? Because that can't be done in 8 cycles, which is the upper limit
for a single instruction. In practice return addresses are often "manually" stashed on the stack, to allow nested
function calls to work).</small></p>
<p>A "function pointer" in SLANG is just a number like any other. (In fact, SLANG doesn't <i>really</i> have types at all: every
value is a 16-bit word). This
means that when our interpreted program calls a function, all we get to know is what number it is trying to call.</p>
<p>This presents 2 problems:</p>
<p><ol>
<li>When our interpreted code makes a function call, we need to obey the calling convention in case it is calling
out to a compiled function (e.g. in library code).</li>
<li>Sometimes library code can call back into our interpreted code, so our interpreted functions need to
be callable with ordinary calling convention.</li>
</ol></p>
<p>I made the <tt>FunctionDeclaration</tt> parser <a href="https://github.com/jes/scamp-cpu/blob/ff2a7c71e311bbf9c39a5218426258ed2a60cb26/sys/slangi.sl#L1080">create a machine-code shim</a> for the
function. The shim calls a function evaluator, passing it
a pointer to the arguments, a pointer to the list of argument names, and a pointer to
the AST for the function body. The function evaluator sets up the new local scope and uses <tt>eval()</tt> to
evaluate the body.</p>
<p>This way each function declared in the interpreted code still has its own entry point, and can still
be called with ordinary SCAMP calling convention, which means compiled functions and interpreted functions can
interact freely.</p>
<p><h2>break, continue, return</h2></p>
<p><tt>break</tt>, <tt>continue</tt>, and <tt>return</tt> are challenging, in that they can require jumping
a long way up the interpreter's call stack. It would be most inconvenient if every single evaluator had to
have special code to notice when an <tt>eval()</tt> call is asking for a <tt>break</tt>, <tt>continue</tt>, or <tt>return</tt>, and manually pass the condition upwards.</p>
<p>My solution was to use <tt>longjmp</tt>. (I like to say that <i>longjmp is my goto</i>).</p>
<p>The evaluator for a <tt>LoopNode</tt> uses <tt>setjmp</tt> to set globals
for <tt>BREAK_jmpbuf</tt> and <tt>CONTINUE_jmpbuf</tt>. The evaluator for a <tt>BreakNode</tt> simply
<tt>longjmp</tt>s to the <tt>BREAK_jmpbuf</tt>:</p>
<p><pre><code>BreakNode = func() {
    return [EvalBreakNode];
};
EvalBreakNode = func(n) {
    longjmp(BREAK_jmpbuf, 1);
};
 
EvalLoopNode = func(n) {
    ...
    setjmp(CONTINUE_jmpbuf);
    if (!setjmp(BREAK_jmpbuf)) {
        while (eval(cond))
            if (body) eval(body);
    };
    ...
};</code></pre></p>
<p>There is a similar setup in the function evaluator for writing a <tt>RETURN_jmpbuf</tt>.</p>
<p>So whenever a <tt>BreakNode</tt> is evaluated, it <tt>longjmp</tt>s to the <tt>BREAK_jmpbuf</tt> which
magically puts control straight back into <tt>EvalLoopNode</tt>, regardless of how many other stack frames are
in the way.</p>
<p>There is a small amount of book-keeping to make sure nested loops and nested function calls unwind correctly,
but overall I think it is quite elegant.</p>
<p>I reused the <tt>longjmp</tt> implementation from <a href="https://incoherency.co.uk/blog/stories/scamp-kernel.html">the kernel</a>. All it does
is that <tt>setjmp</tt> copies the stack pointer and return address into the <tt>jmpbuf</tt>, and <tt>longjmp</tt>
restores them. The result of a <tt>longjmp</tt> is that the <tt>setjmp</tt> call returns a second time. The
first time (when the <tt>jmpbuf</tt> is created) it returns 0. When returning because of a <tt>longjmp</tt>, it
returns the value that was passed as an argument to <tt>longjmp</tt> (1, in the example above).</p>
<p><h2>Benchmarking</h2></p>
<p>Using the same benchmark program as <a href="https://incoherency.co.uk/blog/stories/scamp-list.html">last time</a>, we can
add "SLANG (interpreted)" to the chart:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3970"><img src="https://img.incoherency.co.uk/3970/thumb"></a></p>
<p>And we see that we get the best of both worlds! The growth rate as <i>N</i> increases is comparable
to that of compiled SLANG code, but the fixed overhead is comparable to that of Lisp, because we don't
have to waste time on the compiler and assembler. The runtime is almost constant in this example because
it is dominated by the fixed overheads.</p>
<p>We can get a better idea of the
differences between the compiled and interpreted SLANG implementations if we compare the overall
runtime for a more complex program. This one naively calculates primality of all
integers from <i>2</i> to <i>N</i>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3971"><img src="https://img.incoherency.co.uk/3971/thumb"></a></p>
<p>And now we see that the interpreted code only becomes a worse proposition than the compiled code
once the overall runtime exceeds about 45 seconds.</p>
<p>In general I've observed that the interpreted code runs about 2x-4x slower than the compiled code,
but we get to save spending 20+ seconds on compilation.</p>
<p>In my <a href="https://www.youtube.com/watch?v=74K00OIcAWA">Advent of Code video</a>, the
solution for part 2 ran in <b>1m35s</b> in the interpreter. The compiler took 52 seconds and the
compiled code took 38 seconds, for a total of <b>1m30s</b> for the compiled version,
so the compiled version won, but only slightly. On the sample input the
interpreted version is a big win.</p>
<p>I think this is actually a much better outcome than Lisp would have been, even if the Lisp interpreter
was fast, because it means for any given program I get to decide whether I want it
to start up quickly to test small changes (use the interpreter) or whether I want it to run
as fast as it possibly can on larger inputs (use the compiler), without having to make any
changes to the source file.</p>
<p><h2>Memory overhead</h2></p>
<p>Speed isn't the only reason to prefer the compiler. The interpreter is the <a href="https://gist.github.com/jes/15d2b81c6c38725d3ebfd64d05f7f673">largest SCAMP binary
yet made</a>, weighing
in at almost <b>25K words</b> (the next biggest is the assembler at 20K).
Loading the interpreter basically halves the size of your Transient Program Area before you've
even started, and you also have the size of the AST on top of that.
For quick tests on small inputs that's not usually a problem, but it is something
to bear in mind.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/slang-interpreter.html</link>
   <guid>http://incoherency.co.uk/blog/stories/slang-interpreter.html</guid>
   <pubDate>Wed, 10 Aug 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>A Lisp interpreter for SCAMP</title>
   <description><![CDATA[Lisp has been the most recent step in my search for the ultimate SCAMP programming environment.
Unfortunately what I have so far is so slow that it's probably another dead-end. It's about 300x
slower than compiled SLANG code.]]></description>
   <content:encoded><![CDATA[<p>Lisp has been the most recent step in my search for the ultimate SCAMP programming environment.
Unfortunately what I have so far is so slow that it's probably another dead-end. It's about 300x
slower than compiled SLANG code.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3965"><img src="https://img.incoherency.co.uk/3965/thumb"></a></p>
<p>You can play with it in <a href="https://incoherency.co.uk/scamp/">the emulator</a>. Just
type <tt>lisp</tt> at the shell to get into the Lisp REPL.</p>
<p>(Note that I think I recently made some bugs; it seems to try to evaluate spurious code after it completes
evaluating larger forms. I'm not going to bother fixing it because I'm probably not going to use it,
but if you play with it and think it acts funny... that's why).</p>
<p><h2>Types and garbage collection</h2></p>
<p>Almost everything in Lisp is made of "cons cells". A cons cell is just something that has 2 fields,
that can each point to either <tt>NIL</tt> (the empty list), or to another cons cell. The 2 fields
are called <tt>car</tt> (contents of address register) and <tt>cdr</tt> (contents of decrement register)
due to the IBM 704 which Lisp was originally created for in the 1950s.</p>
<p>In practice we want to be able to store things other than cons cells (e.g. we want to represent
integers without some complicated encoding made out of cons cells). For this reason I have
established the convention that if the <tt>car</tt> field is nonzero, but less than 256, then
it is a <i>type identifier</i> rather than a pointer to a cons cell. This is perfectly safe because
the first 256 addresses in SCAMP memory are the bootloader ROM, so there can never be actual
cons cells created at those addresses. Where the <tt>car</tt> field indicates that a cell has a non-cons-cell type,
the <tt>cdr</tt> field is specific to that type. For integers it contains the raw integer. For
strings it contains a pointer to the string, etc.</p>
<p><table border>
<tr><th>type</th><th>id</th></th><th>notes</th></tr>
<tr><td>NIL</td><td>0</td><td>used for empty list and "false"</td></tr>
<tr><td>SYMBOL</td><td>2</td><td><tt>cdr</tt> points to interned string containing symbol name</td></tr>
<tr><td>INT</td><td>4</td><td><tt>cdr</tt> is raw integer value</td></tr>
<tr><td>BIGINT</td><td>6</td><td>unimplemented</td></tr>
<tr><td>VECTOR</td><td>7</td><td>unimplemented</td></tr>
<tr><td>STRING</td><td>10</td><td><tt>cdr</tt> points to string; only string constants supported for now</td></tr>
<tr><td>HASH</td><td>12</td><td>unimplemented</td></tr>
<tr><td>CLOSURE</td><td>14</td><td><tt>cdr</tt> points to cons structure containing function body, argument names, and parent scope pointer</td></tr>
<tr><td>BUILTIN</td><td>16</td><td>functions implemented in SLANG, <tt>cdr</tt> is SLANG function pointer</tt></tr>
<tr><td>PORT</td><td>18</td><td>essentially a boxed file descriptor</td></tr>
<tr><td>CONTINUATION</td><td>20</td><td>not accessible within the Lisp programs, just used for trampolined style</td></tr>
<tr><td>MACRO</td><td>22</td><td>similar to CLOSURE, except the value returned is then itself evaluated (this is not the correct way to implement Lisp macros, because you pay the macro execution cost every time you call it, instead of only once)</td></tr>
</table></p>
<p>My Lisp interpreter uses a mark-and-sweep garbage collector. In order to be able to "mark"
a cons cell, we need some way to store 1 bit of information in the cell. Given that each
cons cell contains 2 fields, I established the convention that they are always allocated
at even addresses. That way, any pointer to a cons cell is always an even number. If we also make
sure that all of the type identifiers are even numbers, then every value that can legitimately
be stored in a <tt>car</tt> field is an even number. We can now use the least-significant bit of the
<tt>car</tt> field to let the garbage collector mark the cells that are accessible from the environment.</p>
<p>So the garbage collector looks in the current scope, and every scope in the call stack, and recursively marks
all accessible cons cells as "used". Having done this, it sweeps through the arenas that cons
cells are allocated in, frees any that are now unused, and clears the mark bit from cells that are still used.</p>
<p>The garbage collector is invoked at the top of the <a href="https://github.com/jes/scamp-cpu/blob/master/sys/lisp.sl#L975"><tt>EVAL()</tt></a> loop if there are fewer than 100 free
cells. That ensures there are always enough cells to do the work of one <tt>EVAL()</tt> iteration.
This is an idea that I got from <a href="http://www.ulisp.com/show?1BD3">ulisp's garbage collector</a>.</p>
<p>Before I came across the ulisp example, my first idea was that I would invoke the garbage collector from
<tt>cons()</tt> if ever anything tried
to allocate a cell and there were 0 free cells available. The problem with that approach is that some
parts of the interpreter need to construct objects consisting of several cons cells, and it's bad if
the garbage collector frees some of the cells halfway through constructing an object that isn't yet
linked into the program's environment. Having a single defined place that the garbage collector can
be invoked from makes reasoning about its semantics much easier.</p>
<p><h2>Trampolined style</h2></p>
<p>The natural way to write the interpreter is to make <tt>EVAL()</tt> recursive. Unfortunately this
means you need arbitrarily-large amounts of stack space in order to support arbitrarily-deep recursion,
and we don't want to have to make a commitment ahead-of-time as to how much space we allocate for the
stack and how much for the heap.</p>
<p>My solution for this was to make <tt>EVAL()</tt> iterative, and store the Lisp program's "call stack"
in a linked list made up of cons cells. This is quite pleasing in many ways because it helps to
ensure that every reachable object is reachable from the cons cells in the program's environment.</p>
<p>Some parts of the interpreter need to call <tt>EVAL()</tt> on some Lisp form, and then do something
with the computed value. The solution for this is to push onto the call stack a "continuation", which
is just a SLANG function pointer and some associated state.
Every time <tt>EVAL()</tt> finishes evaluating a Lisp form, it pops the calling continuation off
the stack and passes control to it. I found out later that this is called "trampolined style".
It is quite a flexible way to handle control flow, and for example it makes tail-call optimisation
very easy.</p>
<p>Unfortunately it makes for control flow that is extremely difficult to understand. But I think it's just complicated
because it's complicated. It's not obvious that there is an elegant way to implement it.</p>
<p><h2>Benchmarking</h2></p>
<p>I wrote a short program to test primality of an integer, in both SLANG and Lisp. (It does it
the stupid way: just test for divisibility by odd numbers up to <i>sqrt(n)</i>).</p>
<p>Here's a chart showing overall runtime for both the SLANG and the Lisp version, with the time
for the SLANG version <i>including</i> the time it took to run the compiler, and the time in
all cases being measured from hitting enter at the shell prompt to getting back at the
shell prompt (i.e. including process switching overhead, which occurs twice if we need to
run the compiler).</p>
<p><a class="img" href="https://img.incoherency.co.uk/3964"><img src="https://img.incoherency.co.uk/3964/thumb"></a></p>
<p>The time to run the SLANG program is dominated by the time it takes to compile it, in all tested
inputs.</p>
<p>You can see that even with compilation time included, running the Lisp program takes longer
as soon as we get up to about N=3000. In other words, if you have a program
that does ~30 iterations of a trivial loop, you're better off writing it in SLANG <i>even
though it takes 20 seconds to compile</i>.</p>
<p>If you subtract out the compilation time and process-switching time, then the largest input
I tried takes about 60 seconds in Lisp versus 0.2 seconds in SLANG. So the Lisp interpreter is
about 300x slower. I put this down to the complicated trampolined style, and the fact that every
operation involves allocation of multiple cons cells.</p>
<p><h2>What's next?</h2></p>
<p>I'm still after a better SCAMP development workflow. My main issue is that it takes too long
to compile a program to test small changes.</p>
<p>I think I've ruled out both Lisp and my interactive <a href="https://incoherency.co.uk/blog/stories/scamp-development-environment.html">SLANG
REPL</a> that compiles each line of code as it's typed. Lisp because it's too slow, and the SLANG REPL because
it's too much of a footgun.</p>
<p>Maybe the next idea is to write a SLANG interpreter. That way I could run the program in the interpreter
on small inputs, and only when satisfied that it is correct do I need to invoke the compiler in order to
make it run faster. This has the benefit that we don't need to pay the compilation time on small inputs,
but we get to use exactly the same program to get the fast runtime on large inputs.</p>
<p>Probably the way to do this is to rip the parser out of the compiler, have it construct an abstract syntax tree,
and then interpret the AST with a straightforward recursive evaluator. I think the overhead of the
trampolined style is too much to be worth paying, and besides SLANG code doesn't tend to recurse anywhere near
as aggressively as Lisp code.</p>
<p>Unlike with the Lisp interpreter, I wouldn't try to make it "safe". SLANG code is inherently unsafe. I think
if the interpreted program tries to do something that would run off and crash in the compiled code, it's
perfectly fine for the interpreter to run off and crash as well. That means we don't need the interpreter to waste
time on type checks and bounds checks. It'll just straightforwardly do the same thing that the compiled program
would do, for example if you try to call an uninitialised function pointer.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/scamp-lisp.html</link>
   <guid>http://incoherency.co.uk/blog/stories/scamp-lisp.html</guid>
   <pubDate>Wed, 03 Aug 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Cheating at chess with a computer for my shoes</title>
   <description><![CDATA[I have come up with a new way to win at chess:
I have connected up a Raspberry Pi Zero in my pocket to some buttons and vibration motors in my shoes,
so that I can surreptitiously communicate with a chess engine running on the Pi. The project is called "Sockfish" because
it's a way to operate Stockfish with your socks.]]></description>
   <content:encoded><![CDATA[<p>I have come up with a new way to win at chess:
I have connected up a Raspberry Pi Zero in my pocket to some buttons and vibration motors in my shoes,
so that I can surreptitiously communicate with a chess engine running on the Pi. The project is called "Sockfish" because
it's a way to operate <a href="https://stockfishchess.org/">Stockfish</a> with your socks.</p>
<p>The feet are ideal for this sort of thing, because they're the only part of your body that has any sensible degree
of dexterity while still being invisible to casual observers.</p>
<p>There
is prior art for <a href="https://en.chessbase.com/post/yet-another-case-of-cheating-in-chess">phones taped to legs</a> and
<a href="https://www.chess.com/news/view/alleged-cheater-expelled-from-spanish-tournament">some sort of TV remote control (?)</a>
and lots of cases of just going to the toilet and looking at chess positions on phones, but I think Sockfish may be the first
hands-free method that does not require third-party assistance.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3947"><img src="https://img.incoherency.co.uk/3947/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3950"><img src="https://img.incoherency.co.uk/3950/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3940"><img src="https://img.incoherency.co.uk/3940/thumb"></a></p>
<p>Each shoe insert has two <a href="https://en.wikipedia.org/wiki/Force-sensing_resistor">force-sensing resistors</a> and one vibration
motor. The force-sensing resistors are used as buttons to allow me to input my opponent's moves. The vibration motors are used for haptic feedback of accepted button
presses, and to communicate the engine's moves to me so that I can play them on the board.</p>
<p>On Tuesday evening I finally had a chance to deploy Sockfish in a real game against an unsuspecting opponent! <a href="https://odavi.es">Owen</a> is
quite a bit better at chess than I am. I talked him into playing a game with time control of 15 minutes per side, which is
longer than the blitz & bullet that we normally play, but necessary to give me enough time to type the moves with my feet.</p>
<p><h2>First game</h2></p>
<p>Owen was very confused about why it took me 20 seconds of intense concentration to decide on my very first move. He eventually surmised that
I must have "revised" and was concentrating hard to make sure I remembered the theory. In actual fact I was concentrating very hard
to make sure I understood Sockfish's outputs correctly and gave my inputs correctly! I found that I concentrated much harder operating
Sockfish than I do when I'm playing chess the hard way. Maybe I'd play better if I concentrated harder.</p>
<p>It was all going well until we reached a position where Sockfish
was telling me to make an illegal move.
The game (as understood by Sockfish) proceeded as <a href="https://lichess.org/cmcYJF7G">https://lichess.org/cmcYJF7G</a> (with me playing black). It wanted me to play
<b>20... Qxe6</b>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3952"><img src="https://img.incoherency.co.uk/3952/thumb"></a></p>
<p>But on the real board the position was different.  
<a href="https://twitter.com/ruaribush">Ruari</a> was spectating, and already knew about the ruse, so he had contrived to record parts of the game. From his video, the real position was this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3953"><img src="https://img.incoherency.co.uk/3953/thumb"></a></p>
<p>The difference from the Sockfish version is that my <b>g</b> pawn has moved to <b>g6</b>, and my light-squared bishop has not captured on <b>g2</b>.</p>
<p>I think what must have happened is that when the computer asked me to play <b>Bxg2</b> I instead played <b>g6</b>. This is not as crazy as it sounds:
normally Sockfish tells me the starting square and destination square for the move it wants me to make, but
since only one piece could move to <b>g2</b>, Sockfish only needed to communciate the destination square. So it sent <b>g2</b>, but I heard <b>g6</b>. This
is because a "2" is transmitted as 2 short pulses of vibration on the right foot, and to save time a "6" is transmitted as a long pulse (representing 5) followed
by a short pulse. I simply mistook the first short pulse on the right foot for a long pulse, and assumed I should play <b>g6</b>.</p>
<p>Maybe this diagram of the vibration pulses will help (or maybe it won't):</p>
<p><a class="img" href="https://img.incoherency.co.uk/3959"><img src="https://img.incoherency.co.uk/3959/thumb"></a></p>
<p>Anyway, with Sockfish now out the window, I had to continue on my own.</p>
<p>Instead of illegally capturing the queen on <b>e6</b> (which I judged that I would be unlikely to get away with),
I blocked the check with the rook. This was foolish in the extreme! The rook is simply captured with no compensation. In my defence I had been concentrating so hard on communicating with Sockfish
that I scarcely had any comprehension of the actual chess position. We soon ended up at this position and I resigned:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3951"><img src="https://img.incoherency.co.uk/3951/thumb"></a></p>
<p><h2>Second game</h2></p>
<p>Thankfully, the jig still wasn't up, and Owen agreed to a rematch.</p>
<p>Ruari filmed almost the entire game this time.
I remember being paranoid that it would be obvious that I was fidgeting, but in
the video it just looks like I'm thinking really hard. I don't think anyone would guess that I was using trick shoes.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3948"><img src="https://img.incoherency.co.uk/3948/thumb"></a></p>
<p>At one point during this game I made an input
mistake, but I noticed it before it became a problem! I was seen to mouth a swear word, think
hard for 30 seconds, start laughing, and then ask Owen to remind me about the previous couple of moves.
It's a wonder he didn't suspect anything.</p>
<p>After spending 70 seconds secretly undoing and redoing moves with my toes (all while trying to act natural) I eventually convinced myself that I had recovered the position and proceeded, with
an audible "phew!" and an announcement that I needed to stay focused.</p>
<p>Unfortunately, a couple of moves later, disaster struck once more! Sockfish again asked me to play an illegal move.
The position in Sockfish was this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3954"><img src="https://img.incoherency.co.uk/3954/thumb"></a></p>
<p>But the position on the real board was this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3955"><img src="https://img.incoherency.co.uk/3955/thumb"></a></p>
<p>Basically <b>27... Qxe1</b> and <b>28. Rxe1</b> had gone missing from Sockfish's version while I was undoing and redoing moves. I must have undone 2 ply
too far and failed to reconstruct it.
In this position Sockfish was asking me to play <b>Rd8+</b>, but since I didn't have a rook on the <b>d</b> file, this proved challenging.
I announced that I was now "off-piste" (without explaining what that meant), and started playing manually.</p>
<p>Fortunately, being a queen up, the game pretty much won itself, and Owen resigned a few moves later. Not exactly the great
success that I had in mind for Sockfish, but at least it was a win! 50% of the time, it wins every time.</p>
<p><h2>Grand reveal</h2></p>
<p>Immediately after winning the game, I explained the ruse to Owen. His first reaction was incredulity, until I showed him
the shoe inserts and computer. Overall he took it pretty well.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3950"><img src="https://img.incoherency.co.uk/3950/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3949"><img src="https://img.incoherency.co.uk/3949/thumb"></a></p>
<p>I told him that I was planning to recruit a "plausibly-good" chess player to use the shoes to win the world championship, but he considered
that this may "bring the game into disrepute" and said he would definitely dob me in. I think I'd be more interested in the Netflix
adaptation than the real-life story anyway.</p>
<p><h2>Details</h2></p>
<p>In my pocket is a plastic box containing the Raspberry Pi Zero, a 4-channel ADC for reading the force-sensing resistors, some transistors
to switch power to the vibration motors, and a trimpot for each vibration motor to adjust the strength. Without the trimpots they are very loud
and might give the game away (so to speak) prematurely. This is what's inside the plastic box:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3938"><img src="https://img.incoherency.co.uk/3938/thumb"></a></p>
<p>There's also a USB powerbank in my pocket to run the Pi.</p>
<p>The Pi is running a Python script that reads from the GPIO pins and writes to <tt>stdout</tt>, which is consumed by a Perl script
that reads button presses from <tt>stdin</tt>, reconstructs chess positions, and runs Stockfish, and then writes vibration pulses to <i>its</i> <tt>stdout</tt>,
which are then sent to GPIO pins by a second Python script.</p>
<p>(Why this crazy architecture? I am happier writing the actual program in Perl, but all the Raspberry Pi GPIO examples use
Python... it was just easier this way).</p>
<p>This whole contrivance is running inside <tt>screen</tt> with <tt>-L</tt> so that the output is logged for perusal later. It's started
by <tt>/etc/rc.local</tt> when the Pi boots up.</p>
<p>If you have the shoe inserts plugged in while the Pi is booting, then one of the vibration motors stays stuck on for about a minute,
because it turns out that the GPIO pin that drives it is initialised to +5v while the Pi boots up. Doesn't really matter, but you
can feel the vibration get weaker over the course of the minute as it heats up and the resistance increases.</p>
<p>I used a soldering iron to poke a hole in the cargo pocket of the trousers so that the wires can run down the insides of my trouser legs.</p>
<p>Originally I was using 4-pin <a href="https://en.wikipedia.org/wiki/Phone_connector_(audio)">TRRS connectors</a> to connect the Pi
to the shoes, but I found these were very flakey and unreliable. I replaced them with 4-pin waterproof ebike connectors which work much better
and are not significantly larger.</p>
<p>At first
I was printing the shoe inserts in PLA, which is too stiff and makes it very difficult to walk. I replaced these with flexible TPU
plastic, which worked much better. I also started out with ordinary microswitches, which got damaged when I walked on them, and
replacing them with the force-sensing resistors solved this problem, with the added bonus that I can now adjust the activation force
in software.</p>
<p>Jez pointed out that Sockfish is reminiscent of the <a href="http://physics.ucsc.edu/people/eudaemons/layout.html">Eudaemons'</a>
roulette-beating shoe computer, which is a very impressive project considering the primitive electronics
available in the 1970s.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3960"><img src="https://img.incoherency.co.uk/3960/thumb"></a></p>
<p><h2>Sockfish-ng</h2></p>
<p>Don't tell anyone, but I already have plans for a better version of Sockfish that will be much harder to detect!</p>
<p>This proof-of-concept only needed to fool my mates, in a pub, for
the duration of 2 games. To win the world championships we're going to have to get much more serious.</p>
<p>I'm thinking
we'd integrate the Pi and all the other electronics onto a single PCB, instead of having a normal Pi plugged into 2
pieces of stripboard. We'd put this compute PCB in one of the shoes. Each of the shoes would have its own battery and Bluetooth
(or similar) radio inside, and all of the electronics would be hidden under the in-sole which would be glued down.
Even strip-searching the player would not reveal any secrets.</p>
<p>The interface would work
similarly to how it already does, maybe with better distinction between a long pulse and a short pulse, except the communication
from the secondary shoe would go over the radio instead of a wire.</p>
<p>You'd probably have to X-ray the shoes to find out something is up. If that is a realistic threat then I think the
plan is to have the player walk in wearing ordinary shoes, have someone else smuggle in the hacked shoes through a different route,
and have the player swap shoes once he's already been scanned.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/sockfish.html</link>
   <guid>http://incoherency.co.uk/blog/stories/sockfish.html</guid>
   <pubDate>Sat, 30 Jul 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Do I really want a lambda calculus cyberdeck?</title>
   <description><![CDATA[A cyberdeck is an inconvenient portable computing device, often with a retro sci-fi aesthetic.
Lambda calculus is an inconvenient mathematical model of computing. A lambda calculus cyberdeck, therefore,
is an inconvenient device for inconvenient computing.]]></description>
   <content:encoded><![CDATA[<p>A cyberdeck is an inconvenient portable computing device, often with a retro sci-fi aesthetic.
Lambda calculus is an inconvenient mathematical model of computing. A lambda calculus cyberdeck, therefore,
is an inconvenient device for inconvenient computing.</p>
<p>I envision a handheld device, maybe a bit bigger than a scientific calculator, and with a bigger screen
and fewer keys. Here's my concept sketch:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3925"><img src="https://img.incoherency.co.uk/3925/thumb"></a></p>
<p>I want you to imagine that instead of a crude freehand sketch, you are looking at a beautiful 3D rendering
with maybe a shiny metal case and some cool diagonal air vents on the side.</p>
<p>Then we can imagine that the keys have satisfying Cherry MX blue switches, the display is maybe e-Ink,
or something else equally cool-looking (because looking cool is most of the point of a cyberdeck), and
there's an integrated battery with USB charging. I also thought it would be cool to have a lambda calculus
reference sheet that slides into the back of the case.</p>
<p>The runtime could have some way to detect when the final evaluation of an expression is a <a href="https://en.wikipedia.org/wiki/Church_encoding">Church
encoding</a> and pretty-print the output, and maybe it could accept input over USB serial to save
me from having to type everything out perfectly every time I want to test it.</p>
<p>There are just a small handful of problems.</p>
<p><h2>Lambda calculus problems</h2></p>
<p>It turns out that programming directly in lambda calculus is really hard. I actually don't know
how to do it yet, so the stuff I wrote on the display in the concept sketch may be meaningless.
(I think <tt>(&lambda;x.&lambda;y.x)x</tt> means something like "a function of x that returns a function of y that returns x, applied
to the symbol x", which would yield a function that ignores its argument and always returns our symbol x?).</p>
<p>You <i>can</i> add useful features
to lambda calculus (such as support for numbers, and functions that take more than one argument) but those
things aren't strictly necessary.
And besides, if you carry on down that road then you just end up at Lisp. And noone wants a Lisp machine cyberdeck.</p>
<p>And to be honest, being difficult to program is a big part of the appeal for me, so maybe this isn't such a bad thing.</p>
<p>I was struggling with how to handle variable names, but I think what I've settled on is that the only letter
available is <b><i>x</b></i>, and you make other variable names by appending apostrophes, so you can have <b><i>x</i></b>,
<b><i>x'</i></b>, <b><i>x''</i></b>, etc. (copied from the "austere" version of <a href="https://en.wikipedia.org/wiki/Typographical_Number_Theory">typographical
number theory</a>). This way we only need 2 keys to express arbitrarily many variable names, with no ambiguity about the end of one
name and the start of the next.</p>
<p><h2>Display problems</h2></p>
<p>Most of the electronics and software is easy enough (take input from the keypad, handle line editing, evaluate lambdas), so everything
only really has to fit around operating the display.</p>
<p>I have a Pimoroni "inkyWHAT" 400x300-pixel e-Ink display lying around unused.</p>
<p>The inkyWHAT is intended for use with a Raspberry Pi. I'd rather not drive the display with a Raspberry Pi though, that seems
a bit too heavyweight. I'd rather this thing wasn't secretly running Linux underneath.</p>
<p>I also have a <a href="https://www.raspberrypi.com/documentation/microcontrollers/raspberry-pi-pico.html">Raspberry Pi Pico</a> lying around,
which might be suitable for the cyberdeck.</p>
<p>So far I have tried to program the Pico using <a href="http://micropython.org/">MicroPython</a> in <a href="https://thonny.org/">Thonny</a>,
but I found it to be a pretty bad experience. Firstly because the Python library for driving the
inkyWHAT is only compatible with a normal Raspberry Pi, which for a Pico means
ripping out all the parts that use <tt>numpy</tt> and <tt>RPi.GPIO</tt>, and rewriting them to suit MicroPython.</p>
<p>Secondly I found that either Thonny or MicroPython or both are pretty buggy.
There seems to be only a very weak
link between the code shown in the IDE and what is running on the hardware.
The code you type
in your main file seems to be reloaded OK whenever you click the green "RUN" button, but any code you put in other module files seems to be loaded only the first time you use that module,
and subsequent changes have no effect until you unplug it and plug it back in. Even the big red "STOP" button doesn't do the trick.</p>
<p>After spending a couple of hours (unsuccessfully) porting the inkyWHAT display driver to MicroPython for the Pico, I concluded
that I was going too far into yak-shaving and gave up.</p>
<p>Probably I'd just
use a Pi Zero and tolerate the fact that it takes a couple of minutes to boot up. Or maybe stick with the Pico but
write everything in C instead. The Pico's C SDK installation instructions don't look too complicated,
but they are more complicated than "launch the Arduino IDE", which is what I'm accustomed to.</p>
<p>So the question is: do I really want a lambda calculus cyberdeck?
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/lambda-calculus-cyberdeck.html</link>
   <guid>http://incoherency.co.uk/blog/stories/lambda-calculus-cyberdeck.html</guid>
   <pubDate>Wed, 13 Jul 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Eldood: what Doodle used to be</title>
   <description><![CDATA[I have made Eldood as a replacement for
Doodle, because Doodle is now shit. If you used to like Doodle but have grown
frustrated with it, try Eldood.]]></description>
   <content:encoded><![CDATA[<p>I have made <a href="https://eldood.uk/">Eldood</a> as a replacement for
Doodle, because Doodle is now shit. If you used to like Doodle but have grown
frustrated with it, try Eldood.</p>
<p>If you don't know: Doodle used to be a very simple tool for coordinating social occasions. One
person would create a "Doodle poll" listing proposed dates, and everyone
else would tick the dates they could attend, so you can select an optimal
date for the event. It beats the game of "can you make this date?", "no,
I have another thing on, how about the day after?", "Fred can't make
that, what about this other date?", and so on.</p>
<p>Unfortunately, like so many previously-great products, Doodle has slowly
got worse over time and is now your standard corporate
bloatware.
I guess when you have a good product and people like it, the natural
response is to change it until they don't. Doodle used to just do
dates, but it now seems to be more focused on times-of-day, which hinders
the original purpose because you can now only see 7 days at a time instead of an entire month.
The straw that broke
the camel's back is that they now require email addresses from all poll
respondents. Doodle is now shit. They should have left it alone.</p>
<p>So Eldood is what Doodle used to be. It's <a href="https://github.com/jes/eldood">on github</a>.</p>
<p>The backend is a <a href="https://mojolicious.org/">Mojolicious</a> application
that stores data in a <a href="https://www.sqlite.org/index.html">SQLite</a> database.</p>
<p>At first I was going to make a table that joins
a respondent to a single date and a poll, but in the end I went with "CSV-within-a-column"
because normalising it seemed more complex for no reason.
Each response is a single row in the <tt>responses</tt> table, with
a column called <tt>dates</tt> that has values like <tt>20220630,20220701,20220702</tt>.</p>
<p>To provide the "ifneedbe" option, dates in this column can have parentheses around them.
It's not pretty but it is quick and easy.</p>
<p>And, crucially, it is better than Doodle.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3922"><img src="https://img.incoherency.co.uk/3922/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3923"><img src="https://img.incoherency.co.uk/3923/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/eldood.html</link>
   <guid>http://incoherency.co.uk/blog/stories/eldood.html</guid>
   <pubDate>Fri, 01 Jul 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Consciousness is computable</title>
   <description><![CDATA[At first I thought it was quite surprising that consciousness can exist in the first place. It doesn't seem
to be the same sort of thing as anything else that exists. But there's
an enormous selection bias here: every possible universe in which consciousness can not exist does not contain
anybody wondering why it doesn't exist. The only time you can even ask the question is when it already
exists. So in that sense it's not at all surprising that consciousness exists, it is in fact guaranteed!]]></description>
   <content:encoded><![CDATA[<p>At first I thought it was quite surprising that consciousness can exist in the first place. It doesn't seem
to be the same sort of thing as anything else that exists. But there's
an enormous selection bias here: every possible universe in which consciousness can not exist does not contain
anybody wondering why it doesn't exist. The only time you can even ask the question is when it already
exists. So in that sense it's not at all surprising that consciousness exists, it is in fact guaranteed!</p>
<p>And Matt pointed out that the universe actually contains many surprising things. Electricity, magnetism,
gravity, fire, light, planets, trees, boats, computers, and so on. These are all very strange and surprising things
that you probably couldn't imagine if you didn't already know about them, and yet they exist in our
universe with no trouble at all.
Why should consciousness be any
different? And yet consciousness does feel different. All of the other things happen, apparently,
completely mechanically, even if the mechanisms are complicated. But consciousness has a mind of its own.</p>
<p><h2>What do I mean by consciousness?</h2></p>
<p>By "consciousness" I <i>don't</i> mean other related things like emotions, feelings, intelligence, or
decision-making.
I think those things can be explained without any "observer".</p>
<p>I struggle to put into words exactly what I <i>do</i> mean, but I think it should be obvious
to anyone who is actually conscious. I am aware that I exist. I think therefore I am. I have an internal experience,
in which I am the subject of things that happen to me.</p>
<p>Sometimes when I talk to people about consciousness they try to argue that it is an illusion, and
that we're all tricked into thinking we're conscious when we're actually not.
I find
this position self-contradictory.
Consciousness isn't the illusion, consciousness is the <i>audience</i>.
Anyone who has ever been conscious
knows that being conscious is different to not being conscious.</p>
<p>Arguing that there's no such thing as consciousness is like arguing that there's no such thing
as hunger. "Oh, people just <i>say</i> they're hungry when they haven't eaten lately, but nobody
actually <i>feels hungry</i>". But if you've ever felt hungry in your life then you know that
this is false. The same with consciousness: the only way you could seriously believe that
consciousness is an illusion is if you have never experienced it.</p>
<p>And that is a distinct possibility! A <a href="https://en.wikipedia.org/wiki/Philosophical_zombie">p-zombie</a>
is a hypothetical person who looks and acts and seems just like an ordinary person, except they have no
consciousness. There is no internal experience. There is no awareness. A p-zombie takes the same sorts of
inputs as a conscious human, and produces the same sorts of outputs, and for all intents and purposes
<i>appears</i> conscious, but is actually not, and there is no way to tell from the outside.</p>
<p>It is entirely possible that some (or many, or most!) of the people in the world are p-zombies.
<a href="https://en.wikipedia.org/wiki/Solipsism">Solipsism</a> holds that everyone in the world is
a p-zombie, apart from me.</p>
<p>It might sound egotistical to imagine that I may be the only truly conscious being ever to exist, but I don't think
it's that far outside the realms of possibility. After all, I can hear my thoughts and I can't hear yours.</p>
<p>Personally I prefer to live in a world in which other people are real than one in which they are not,
so I discount Solipsism out of hand. Even if I am the only truly conscious being in the universe, I think I get more out
of it by pretending the NPCs are real.</p>
<p><h2>What do I mean by computable?</h2></p>
<p>I thought this was a pretty settled question, with an answer something like "able to be calculated by a Turing machine",
but it turns out there is a field of <a href="https://en.wikipedia.org/wiki/Hypercomputation">hypercomputation</a>
which studies computational models stronger than that of a Turing machine.</p>
<p>But by "computable", I mean "able to be calculated by a Turing machine". For consciousness to be computable,
I mean that it is possible for a Turing machine to create consciousness.</p>
<p>I <i>don't</i> merely mean that it is possible to create a convincing simulation of a consciousness that gives
plausible outputs for any given inputs. That would be a p-zombie. Anyone who is conscious knows there is more to consciousness than just
<i>saying</i> you're conscious.</p>
<p><h2>Argument</h2></p>
<p><b>Premise 1:</b> Everything in the universe is explained by the laws of physics.</p>
<p>By "laws of physics", I mean the complete set of laws that govern the universe. This premise seems almost
tautological.</p>
<p>I think the only way
it might be disputed would be if you argue that there is no set of laws governing the universe, and
literally everything can happen, and does happen, and no laws apply. That the only reason we seem to have laws on a macro
scale is some sort of constructive interference between all the different ways the universe can do everything all at once.</p>
<p><b>Premise 2:</b> Physics is computable.</p>
<p>I'm not sure how to argue this one. Classical physics is computable. Relativity is computable. Quantum mechanics
is computable (even without quantum computing) for whatever finite degree of precision you want. What would non-computable
physical laws even look like?</p>
<p><b>Premise 3:</b> Consciousness exists within the universe.</p>
<p>The best arguments I know of in favour of this premise are:</p>
<p><ul>
<li>everything exists within the universe; that's what it means to be the universe</li>
<li>anaesthetics exist within the universe and are (seemingly) effective at suppressing consciousness, so the consciousness must also exist within the universe</li>
</ul></p>
<p>Alternatively, it could be that the universe is more like the world in a video game, except the player
of the game has their senses hooked up directly to the game at birth, so that they have no way to receive
sensory input from anything outside the game universe. As far as such a player would be concerned, the video game
is all that exists. They would be just as baffled as we are about how consciousness can arise in such
a primitive world.</p>
<p>You could even imagine that anaesthetics exist within the game, except whenever the player in the game receives
anaesthetic, the "real life" player is also injected with anaesthetic (by a robot or diligent minder), such that it appears to the player that the
anaesthetic within the game is fully functional. Arguably it is.</p>
<p>The "video game universe" idea doesn't even require you to assume that everyone else is a p-zombie. Multiplayer games
exist.</p>
<p><b>Conclusion:</b> Consciousness is computable.</p>
<p>If you accept all 3 premises, then I think you have to accept the conclusion. However, the conclusion is
obviously absurd. It seems obvious to me that no amount of computing can create the sensation of
existing as a mind.</p>
<p>So I think this suggests that one of the premises is false, which also seems
surprising, but maybe not quite so much? At least there are 3 times as many places for the surprising
part to be hiding.</p>
<p>Either minds have something that computers don't, or they don't. Neither possibility seems correct.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/consciousness-is-computable.html</link>
   <guid>http://incoherency.co.uk/blog/stories/consciousness-is-computable.html</guid>
   <pubDate>Mon, 20 Jun 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The ultimate SCAMP development environment</title>
   <description><![CDATA[I've been thinking about what I want the SCAMP development workflow to look like for
this year's Advent of Code. At first I was planning to do it in FORTH, but I've tried to
get into FORTH several times and haven't got on with it. I like the simple REPL of FORTH but I very
much do not like the language. So the plan is to come up with a way to make a REPL for
SLANG.]]></description>
   <content:encoded><![CDATA[<p>I've been thinking about what I want the SCAMP development workflow to look like for
this year's Advent of Code. At first I was planning to do it in FORTH, but I've tried to
get into FORTH several times and haven't got on with it. I like the simple REPL of FORTH but I very
much do not like the language. So the plan is to come up with a way to make a REPL for
SLANG.</p>
<p>The reason to prefer a REPL over the edit-compile-test workflow is that it saves wasting time
on recompiling and rerunning the entire program every time a small portion changes. In principle
you can update a function definition, and then re-compile and re-run that function, without having
to recompile the rest of the program, or repeat (say) parsing of the input file.</p>
<p>I think it would not be too much trouble to make an environment that lets me type a line of SLANG code
at the command line, and then compiles the code, loads the compiled code into memory, and executes it,
"inside" the process of the development environment.
This wouldn't be compiling a <i>program</i> as such, it would just be a tiny amount of code each time. As long as
we tell the compiler the addresses of all of the known globals, and what the start
address of the code will be, this seems perfectly viable.</p>
<p>Once we have an interactive environment where we can type in single statements and compile and execute them,
there are a number of interesting things we could do:</p>
<p><ol>
<li>Notice declarations of globals and allocate them manually, so that they can be reused in later statements.</li>
<li>Remember the source for each function definition so that it can be edited later without having to type it out from scratch.</li>
<li>Save every input line in a history file so that the history can be manually edited down and turned into a standalone program.</li>
<li>Save the process binary out to a file that can be executed to get back to the current state.</li>
</ol></p>
<p>I have <a href="https://github.com/jes/scamp-cpu/blob/master/sys/rude.sl">already got a rudimentary implementation</a> just to find out how well it works. It's called "RUDE", for something
like "RUDE Ultimate Development Environment". It's only about 350 lines of code. It can notice global declarations,
compile and execute code, and save out the project in both source and binary form.</p>
<p>You can try it out in the online <a href="https://incoherency.co.uk/scamp/">SCAMP emulator</a> if you want, just run <tt>rude</tt> at the shell to get into RUDE.</p>
<p>One advantage over FORTH is that function calls in SLANG always have an extra layer of indirection. This only exists
to simplify the compiler (there's no need for a distinction between ordinary function calls and function pointer calls
if every function is a function pointer... Galaxy brain), but it means when we update the implementation of a function,
all of the callers of that function automatically use the new implementation. In FORTH, callers of a function still use
the old implementation until they are in turn recompiled, which is bad because you can fix a bug and find that your
fix is not actually in use until you track down everything that calls the function that contained the bug.</p>
<p><h2>Current state</h2></p>
<p>Here's an example RUDE session with what I have so far (in the emulator, running about 20x faster than real hardware):</p>
<p><script id="asciicast-3mXMXFpP2o7fGDsq2aaZhYybs" src="https://asciinema.org/a/3mXMXFpP2o7fGDsq2aaZhYybs.js" async></script></p>
<p>(All of the "... 1st pass ..." stuff is spam from the compiler and assembler.) The important things to note in this session are:</p>
<p><ol>
<li>Printing "Hello, world!" using <tt>printf</tt>. The call to <tt>printf</tt> is compiled, then executed. The text "Hello, world!" appears on the console, and we see the return value of 14 from <tt>printf</tt> (the number of characters written).</li>
<li>Declaring a variable "n" and initialising it to 0. The assignment is compiled and then executed. There is no real return value, so the displayed return value of 20960 is some spurious memory address.</li>
<li>Declaring a variable called "f" and initialising it to point at a function that increments "n" and then prints out the value of "n". The function definition and assignment is compiled and then executed, which executes the assignment to "f" (but does not execute the function body).</li>
<li>Calling <tt>f()</tt>. We can see that "n" is incremented with each call (and we get the return value of 20 from <tt>printf</tt>, by accident).</li>
<li>Exiting RUDE (typing <tt>^D</tt> to give EOF on stdin). We now have files <tt>project.sl</tt> and <tt>project</tt>. <tt>project.sl</tt> contains a source listing of the session, and <tt>project</tt> contains a copy of the process binary from memory, taken at runtime after the latest command line input.</li>
<li>Executing <tt>./project</tt> takes us back into RUDE (but with no "RUDE AWAKENING" message, because we're dropped straight back to the REPL, we're not restarting RUDE), <i>with the in-memory state exactly as it was when we exited</i>! Good magic.</li>
<li>Calling <tt>f()</tt> proves that both the function implementation and the value of "n" are retained.</li>
</ol></p>
<p><h2>Killer problems</h2></p>
<p>My current implementation, although it proves the concept (maybe), is not workable for several reasons:</p>
<p><h3>Compiling takes too long</h3></p>
<p>It turns out that it takes over <b>30 seconds</b> (at 1 MHz) to compile the empty string. This means almost all of the compilation
time, for typical statements, is wasted on overhead which is exactly the same every time.</p>
<p>What is this overhead?</p>
<p><ul>
<li>preparing source inside RUDE: ~8 seconds</li>
<li>context switching in the kernel: ~7 seconds</li>
<li>compiler: ~7 seconds</li>
<li>assembler: ~10 seconds</li>
</ul></p>
<p>(Assuming I didn't blunder the profiling).</p>
<p>When we're compiling "the empty string", we're not <i>just</i> compiling the empty string. RUDE also has to provide
names and addresses of globals, of which there are a bit over 200 in a blank environment (mostly the functions in
the standard library). A lot of time is spent formatting and writing these 200 names and addresses (in
RUDE) and reading and parsing them (in the compiler and assembler). I think that accounts for most of the overhead.</p>
<p>The rest of the overhead is context switching in the kernel, which means saving the parent process (RUDE) out to disk,
and reading child processes into memory (compiler and assembler). I've spent quite a lot of time optimising context
switching in the past
so I expect there's not low-hanging fruit here, short of reducing the number of context switches. Currently we have
RUDE swapped out, the compiler swapped in, RUDE swapped back in to do a tiny amount of work, RUDE swapped back out again,
the assembler swapped in, and RUDE finally swapped back in again, which is about 6 lots of reading/writing a
process to disk.</p>
<p><h3>Unknown binary size</h3></p>
<p>When we compile a statement, we need to <tt>malloc()</tt> some space to put it in, and we need to tell the assembler what
the starting address will be (there's not yet any
sensible way to create <a href="https://en.wikipedia.org/wiki/Position-independent_code">position-independent code</a>).</p>
<p>Perhaps you can see the problem here: we don't know what address the code will be placed at until after we've allocated
space, and we don't know how much space to allocate until after we've generated the code, which we can't do until after
we know where it's going to be placed.</p>
<p>Currently RUDE solves this by always allocating 1000 words for every statement. This is bad, both because it is way too
much in the normal case and pointlessly wastes memory, but also plausibly because it could be too small in some cases.</p>
<p><h3>Memory leak for almost all statements</h3></p>
<p>But it's worse than just <i>temporarily</i> allocating too much space for each statement. We're <i>permanently</i>
allocating too much space for each statement!</p>
<p>RUDE has no knowledge at all of what the statements are doing. The only special case it currently supports is that
statements beginning <tt>var</tt> are declarations of globals, which require special handling so that the addresses of
the globals can be tracked.</p>
<p>Lots of statements are completely ephemeral. For example, <tt>printf("Hello, world!\n", 0)</tt> doesn't contain any
data that needs to persist after it has finished executing, so it would be perfectly fine to <tt>free()</tt> the memory
that we put the code in, after it's been executed. But without peering inside the code (and, in turn, peering inside <tt>printf()</tt> to work out
whether it is expecting to keep hold of the string), there's no way to know that the statement doesn't contain static
allocations that need to stick around.</p>
<p>Statements that include function definitions, strings, or array literals contain static allocations, and if executing the
statement results in a reference to one of the aforementioned allocations being kept around somewhere, then it is not
safe to free (all of) the code space because that would result in freeing the memory backing the corresponding function,
string, or array literal.</p>
<p>Currently RUDE just doesn't free anything. The compiled code for every input statement stays in memory forever, even
when no references to it remain. Incidentally, this is the same approach that simpler FORTH implementations take,
as far as I can tell. They just don't even implement <tt>free()</tt>, all allocations take the "HERE" pointer, and
advance it ready for the next allocation. That said, FORTH doesn't have to allocate code space for most input statements, because
they are executed without being compiled.</p>
<p><h2>Killer solutions</h2></p>
<p>We need to solve all of the above 3 "killer problems" in order to turn RUDE into a usable system.
I haven't got a complete picture in mind yet, but I have the following ideas which might form part of it.</p>
<p><h3>"Interpreting" simple statements</h3></p>
<p>Simple statements could be interpreted directly inside RUDE. We already have the table of all known globals. If we did
a tiny amount of parsing, to recognise simple literals and function calls, and throw everything else to the
real compiler, then we could "interpret" simple statements by pushing function arguments onto the stack and then calling
the function pointer that we look up in the globals table.
We might save both execution time, because simple statements aren't compiled, and memory usage,
because we don't need any memory to store code we're not producing.</p>
<p>I definitely want to do this, in the absence of some other great breakthrough that makes compilation effectively
instantaneous (see below).</p>
<p><h3>Put the compiler and assembler inside RUDE</h3></p>
<p>The limit case of interpreting simple statements is to interpret <i>all</i> statements. The easiest way to do this would
be to basically copy and paste the source of the compiler (and assembler) and put them both inside the RUDE process, so
that we never have to context switch, and we already have the table of global names and addresses ready to hand.</p>
<p>This would be an ideal solution, apart from one thing: memory. Currently the RUDE binary is about 15 Kwords,
the compiler is 18K, and the assembler is 20K. That comes to 53K, which is already too much to fit in memory
(taking account of the kernel), let alone any code or data for the user program.</p>
<p>In practice it wouldn't be as bad as that because the library functions would not need to be duplicated. The library
blob comes to 9K, so if we lose 2 copies of that, then we could expect putting the compiler and assembler inside the RUDE
process to bring it up to 35K, which is still on the extremely heavy side.</p>
<p>This idea might be worth playing with anyway, because I can't think of any better way to reduce compilation overhead.
But the memory cost is very high, it certainly wouldn't be workable for the larger
Advent of Code problems. But maybe it could work if I develop in RUDE, get it to work on the sample input, and then turn it
into a standalone program to run on the full input.</p>
<p>If everything were inside the one process, it might also make it easier to defer memory allocation until such a time as the
length of the binary is known.</p>
<p><h3>Give names and address to the compiler and assembler in a better format</h3></p>
<p>Currently the names of globals are passed to the compiler as ordinary SLANG source, like:</p>
<p><pre><code>extern printf;
extern getchar;
extern malloc;
...</code></pre></p>
<p>These are just directives that tell the compiler that a name exists as a global but is declared somewhere else. It's just
a way to say that it's fine
to refer to these globals, even though the compiler didn't see them, because something else is going to
tell the assembler where they live.</p>
<p>Similarly, they are defined for the assembler as ordinary assembler directives, like:</p>
<p><pre><code>.d _printf 0x2f10
.d _getchar 0x2f0a
.d _malloc 0x2e8d
...</code></pre></p>
<p>So that the assembler knows that any reference to <tt>_printf</tt> is actually a reference to <tt>0x2f10</tt>.</p>
<p>The problem with this scheme is that it is designed to be easy for humans to write, and parsing it with the ordinary
parser is very slow. Since this
table is both generated and consumed by the machine, maybe it could be in a binary format which is faster to work with,
and can be parsed with no validation or bounds-checking.</p>
<p>(I care about performance, not security. Fight me. Nobody's complaining that RUDE is a non-viable project because it's
too easy for hackers to break into your SCAMP!).</p>
<p><h3>Stop the compiler from validating names of globals</h3></p>
<p>Rather than create a whole new format for passing globals into the compiler, we could just have a switch to make the
compiler assume that all unrecognised names are valid globals. The downside is that typo'd names won't get rejected
until assembly time, and the message will be slightly more confusing, but it would save us time in the compiler.</p>
<p>It's probably not worth doing because even if we saved 100% of the overhead in the compiler, and 50% of the overhead
in RUDE, it would only knock about 7 seconds (25%) off the total time to compile the empty string.</p>
<p><h3>Have the compiler directly output machine code instead of assembly language</h3></p>
<p>Instead of having the compiler write assembly code, and then passing the assembly code to the assembler to
turn it into machine code, we could have the compiler output machine code directly.</p>
<p>Reasons <i>not</i> to do this include:</p>
<p><ul>
<li>Opcodes can change whenever I change the instruction table, so any code that cares about opcodes needs a system to
keep it updated, which is a hassle. (Although I don't do that much any more, so maybe it's fine to say opcodes are set in stone now).</li>
<li>We'd still need some equivalent to the "2nd pass" of the assembler which touches up addresses that weren't already known
during the first pass. Probably this would be mostly copy-and-pasted out of the assembler and into the compiler.</li>
<li>It's helpful to be able to have the compiler driver (either <tt>slc</tt> or RUDE) pass in its own assembly language
header and footer that can use labels instead of hard-coded addresses. Without a separate assembly step these addresses
would probably have to be patched up in the binary, which is obviously more trouble and less robust.</li>
</ul></p>
<p>But those are small problems.</p>
<p>The assembler accounts for the majority of the runtime in compiling normal programs as well as short statements in RUDE,
so removing it could more than double the compiler throughput. So I probably want to do this.</p>
<p>Then it might be worth revisiting "Put the compiler inside RUDE" because we would save almost the entire memory cost of
the assembler.</p>
<p><h3>Split up lexing and parsing</h3></p>
<p>The parsing framework I use for both the compiler and the assembler does not distinguish between lexing and
parsing. Every input token to the parser is a single character. This introduces quite a lot of overhead because
sometimes the same characters are examined many times until enough backtracking has happened to work out how
to parse them. Historically this was tackled by first tokenising the input (so each character is only examined once)
and then parsing the (much shorter) stream of tokens instead of characters.</p>
<p>I'm not sure how much help this would be. I have structured the parser in both the compiler and the assembler to try
to minimise the amount of backtracking on common inputs. It's possible that separate tokenising would actually make performance worse
because now instead of 1 stream there are 2 streams that need to be consumed!</p>
<p><h3>Compile everything twice</h3></p>
<p>To work out how much memory we need for the code, we could compile it once with a placeholder address, measure how large
it is, make the allocation, and then compile it "for real". This would double the time spent on compiling, which makes
it sound absurd, but in combination with some other solution that makes compiling very fast, it might be the
easy way out.</p>
<p>In principle the size of the generated code can depend on the address it is going to be placed at (because some instructions
have shorter forms for addresses in the top page and the bottom page), but in practice I think it would always be the
same size, because we're not putting code in the top or bottom page.</p>
<p><h3>Make realloc() shrink in-place</h3></p>
<p>Currently <tt>realloc()</tt> always makes a new allocation, copies the data, and then frees the old allocation. But when
you're <i>reducing</i> the size of an allocation, it's always safe to just shrink the existing allocation and return the
unused space to the free space pool.</p>
<p>So we could just allocate a block that's way too large, put our code in it, and then shrink it to fit.</p>
<p>The only reason I haven't implemented shrink-in-place already is that almost every use case I had for <tt>realloc()</tt> involves
<i>growing</i> an allocation to handle more data.</p>
<p>I think making <tt>realloc()</tt> shrink in-place is the best solution to not knowing the binary size ahead of time.</p>
<p><h3>Generate position-independent code</h3></p>
<p>I remembered that I have already written up my thoughts on how position-independent code could work
<a href="https://github.com/jes/scamp-cpu/blob/master/doc/PIC.md">for when I wanted to implement <tt>strace()</tt></a>.</p>
<p>Basically it involves making a no-op function call, so that after it returns you have your Program Counter in
<tt>r254</tt>, and then you know the global offset to where the code is running and can patch up all the
addresses before running the "real" code. It's a bit of a hassle but would work.</p>
<p>So maybe I could do that and then defer allocation until after the code is already compiled? Probably a bad idea,
it seems both more difficult to implement and more wasteful of memory than the "Make <tt>realloc()</tt> shrink in-place" idea.</p>
<p><h3>Manual statement annotation</h3></p>
<p>To solve the problem of wasting memory on side-effect-free statements,
we could require the user to manually annotate "important" statements with an exclamation mark, so that they're not
immediately <tt>free()</tt>'d after execution. This seems error-prone though, I'm not sure it's a good idea.</p>
<p><a href="https://dartoxia.com/">Ben</a> pointed out that the interactive REPL system I'm describing is a bit like
IPython. IPython annotates each statement with a number, and each statement sticks around until manually deleted. Maybe
I could do something like that, where instead of deciding ahead-of-time whether a statement should be <tt>free()</tt>'d
or not, the user just has the option to manually free statements that they no longer care about. This would also
be a good way to manage the SLANG source history without having to manually delete dead-ends.</p>
<p>I don't really like it, but maybe it's not as bad as it sounds? And I don't have any other ideas for how to stop wasting
memory, so maybe it's the best you can do?</p>
<p><h2>Next</h2></p>
<p>So I have a lot of ideas to be pondering, but still no complete picture for how RUDE is going to work.</p>
<p>I think the way to go is to start with the promising ideas that would be useful even if RUDE never works, namely:</p>
<p><ul>
<li>Have the compiler directly output machine code instead of assembly language</li>
<li>Make <tt>realloc()</tt> shrink in-place</li>
</ul></p>
<p>And then at least I've got some benefit out of it, and I can reassess performance and memory usage to
work out whether I want to press on with RUDE or ditch it.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/scamp-development-environment.html</link>
   <guid>http://incoherency.co.uk/blog/stories/scamp-development-environment.html</guid>
   <pubDate>Wed, 15 Jun 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Toolmaker's Clamp</title>
   <description><![CDATA[I have managed to make the toolmaker's clamp that I mentioned last time.
It is made out of mild steel, which is soft for a machinist's tool, but harder than wood, plastic, and aluminium, which
are what I'm normally limited to.
Since I made it, it belongs to me, and a clamp is a type of tool, I suppose this is both a toolmaker's clamp
and a clampmaker's tool.]]></description>
   <content:encoded><![CDATA[<p>I have managed to make the toolmaker's clamp that I mentioned <a href="https://incoherency.co.uk/blog/stories/mini-mill-20220609.html">last time</a>.
It is made out of mild steel, which is soft for a machinist's tool, but harder than wood, plastic, and aluminium, which
are what I'm normally limited to.
Since I made it, it belongs to me, and a clamp is a type of tool, I suppose this is both a toolmaker's clamp
and a <i>clampmaker's tool</i>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3902"><img src="https://img.incoherency.co.uk/3902/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3905"><img src="https://img.incoherency.co.uk/3905/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3906"><img src="https://img.incoherency.co.uk/3906/thumb"></a></p>
<p>It can be used for holding small parts while drilling, filing, tapping, etc., or for transferring multiple parts
between more
substantial workholding arrangements (e.g. the vice on the mill and the vice on the bench) while maintaining their
alignment, and probably for lots of other things.</p>
<p>The way it works is you tighten up the front bolt (which pulls the jaws together) until the clamp is grabbing the work,
and then tighten up the rear bolt (which pushes the jaws apart, it has a small section at the end of the thread turned down to locate in a matching hole) to lever the clamp against the front bolt
and increase the clamping pressure. The knobs have holes in so that an allen key or similar can be used to provide
more torque to the bolts.</p>
<p>I made it out of hot-rolled mild steel bar stock, because it was the most convenient material I had available, so
apart from the 2 bolts, this is what it all looked like before I started:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3910"><img src="https://img.incoherency.co.uk/3910/thumb"></a></p>
<p><h2>Knobs</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/3911"><img src="https://img.incoherency.co.uk/3911/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3904"><img src="https://img.incoherency.co.uk/3904/thumb"></a></p>
<p>Normally on a toolmaker's clamp the knob and the screw thread would be made out of a single piece of material,
with the knobs knurled on the lathe. I don't have a knurling tool and have always found cutting long threads in thin
material to be quite tricky, so I decided to make life easy for myself and use existing M6 bolts, with the knobs
machined separately and pressed on to the heads.</p>
<p>This turned out to be a bad idea, because the knobs ended up wider than the clamp jaws.
This means, for example, it's not possible to use my clamp to hold something perpendicular to
the pillar drill table for drilling, because the knobs prevent the jaws from sitting flat. Fortunately it
won't be any harder to remake the screws now than it would have been to make them in the first place, so I
can always replace the screws if it bothers me.</p>
<p>The jaws are 12mm across, and the head on the M6 bolts is 10mm across. This sketch in
<a href="https://incoherency.co.uk/blog/stories/freecad-vs-solvespace.html">SolveSpace</a> shows that a 10mm hexagon is 11.55mm across
at the widest point:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3901"><img src="https://img.incoherency.co.uk/3901/thumb"></a></p>
<p>So if you want the knob to press onto a 10mm hex head, and you want it less than 12mm in diameter, then you'll have
less than 0.25mm wall thickness, which seems not enough.</p>
<p>I made the knobs with a 5mm end mill, whereas I made the jaws of the clamp with a 10mm end mill. I found that the
5mm end mill gives a much superior surface finish. I'm not sure whether the 5mm tool is made better, or whether
my feeds and speeds were better. I used Bryan Turner's <a href="http://brturn.github.io/feeds-and-speeds/">feeds and
speeds calculator</a> for both tools. Maybe it is just down to the rigidity of the machine.</p>
<p><h2>Flood coolant</h2></p>
<p>I haven't got around to improving the drain on my tub yet, but I ran some of these jobs with flood coolant turned on,
and it worked really well. It did a great job of keeping everything cool and blowing chips away from the work. Since
I haven't fixed the drain, I did end up submerging one of the stepper motor connectors, and nothing bad happened, so it
looks like the coolant is indeed non-conductive. I also haven't noticed any rust developing, so that's good too.</p>
<p>Here's a video of the finishing pass on one of the jaws:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/9fORws5nAsw" frameborder="0" allow="allowfullscreen" allowfullscreen></iframe></p>
<p>I don't know why it makes a horrible noise when cutting in the Y axis but not in the X axis. It should have been taking
the same width of cut on all sides of the part.</p>
<p><h2>Draughting</h2></p>
<p>I've been getting interested in hand draughting lately, so I did a drawing of the toolmaker's clamp jaws while
I was halfway through making them. I'm not sure how legit it is to have one drawing specify 2 slightly different
parts, but I decided it beats having to draw it twice.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3908"><img src="https://img.incoherency.co.uk/3908/thumb"></a></p>
<p>The jaws I made don't <i>exactly</i> match the drawing, but they're quite close.
They're about 96mm long instead of 100mm because of a small blunder
(I forgot to account for the diameter of the tool when zeroing my coordinates, rookie mistake). And the supposed
8mm deep blind hole is actually a through hole, because of another small blunder: I started drilling the hole from the wrong
side, and a blind hole from the wrong side doesn't work, so it had to become a through hole.</p>
<p>At this point I didn't have a sensible way of drawing circles, so the circles are drawn freehand. I think it's OK
apart from the circles.</p>
<p>Here's a poorly-lit photograph showing my homemade draughting equipment:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3893"><img src="https://img.incoherency.co.uk/3893/thumb"></a></p>
<p>The board is an offcut of kitchen cabinet material (MDF with a very smooth paint job). The 30&deg; triangle is
3D-printed, and is only there to assist with the isometric view. The T-square has a 3d-printed board edge follower
on the left hand side, and the transparent plastic ruler is made out of a piece of broken perspex from a picture
frame. The markings are engraved with a drag engraver on the CNC router and then coloured in with Sharpie to make
them black.</p>
<p>It felt a bit absurd to draw a 30&deg; angle in CAD in order to 3d print a triangle to allow me to
draw 30&deg; angles on paper, but it was genuinely the quickest way I could think of to create a 30&deg; triangle.</p>
<p>Since then I have also made a simple compass, so I might be able to draw better circles next time:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3909"><img src="https://img.incoherency.co.uk/3909/thumb"></a></p>
<p>On the underside there is a pin from a pogo pin pressed in with a soldering iron to provide a sharp point.
You just adjust the radius with the wing nut, push the point against the paper,
put the pencil in the hole, and swing it in a circle. I haven't used it in anger yet, so time will tell whether this is
easier or harder to use than a normal compass. It's based on John Heisz's <a href="https://www.youtube.com/watch?v=5owEwcrbe2w">compact compass</a> design.</p>
<p>And I have some vague plans for an ellipse-drawing tool to help me draw circles in the isometric view. There is prior
art for ellipse-drawing tools, but I'm not aware of one that maintains the aspect ratio as you adjust the size. The ones
I've seen have 2 adjustments that you have to adjust together to get the ellipse shape you want, but for
circles in isometric view, you always want the same aspect ratio. So maybe I can invent a new thing here. Or more likely it
already exists and I just haven't found it yet.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/toolmakers-clamp.html</link>
   <guid>http://incoherency.co.uk/blog/stories/toolmakers-clamp.html</guid>
   <pubDate>Tue, 14 Jun 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Progress on the CNC mini mill</title>
   <description><![CDATA[I've made a bit of progress on the CNC mini mill project,
and have made some cuts, although currently it's still not in full working order.]]></description>
   <content:encoded><![CDATA[<p>I've made a bit of progress on the <a href="https://incoherency.co.uk/blog/stories/cnc-mini-mill.html">CNC mini mill project</a>,
and have made some cuts, although currently it's still not in full working order.</p>
<p>The machine is now installed in its tub, with the control cabinet on the wall and the PC on a little desk.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3828"><img src="https://img.incoherency.co.uk/3828/thumb"></a></p>
<p>I've also restrained the cables with a handful of little 3d-printed clips, so that they can't get snagged:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3881"><img src="https://img.incoherency.co.uk/3881/thumb"></a></p>
<p><h2>Motor</h2></p>
<p>I've wired up the spindle motor with an analogue ammeter for a crude "spindle load" display:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3878"><img src="https://img.incoherency.co.uk/3878/thumb"></a><br>
(<a href="https://www.youtube.com/watch?v=1uLdZ0jFPoc">video demo</a>)</p>
<p>I found the spindle load display very useful for "manual" drilling, in the absence of a manual quill.
I can modulate the Z feed rate using the jog pendant (see below) while watching the spindle load,
to maintain cutting load without overloading the motor. It's also helpful generally for knowing how
close a cut is to the limit of the motor. It seems to be fine with anything below 2 amps, but starts to
stall if it exceeds 2 amps for more than a few seconds.</p>
<p>I've fitted one of those magnetic tachometer kits so that I can get a spindle speed display:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3885"><img src="https://img.incoherency.co.uk/3885/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3877"><img src="https://img.incoherency.co.uk/3877/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3880"><img src="https://img.incoherency.co.uk/3880/thumb"></a></p>
<p>For the time being I've just stuck the magnet to the drawbar magnetically. It hasn't flown off and
hit me in the face yet.</p>
<p><h2>PC</h2></p>
<p>I bought and installed the cheapest non-Nvidia GPU I could find on eBay, and it has solved the problem
where OpenGL usage on the integrated GPU would crash the machine. That means I now have access to a much
wider range of LinuxCNC screens, and I'm now on Gmoccapy instead of Qtaxis.</p>
<p>Surprisingly, the LinuxCNC screens seem a lot less mature than
<a href="https://winder.github.io/ugs_website/guide/platform/">UGS Platform</a> does. They all have weird
bugs and strange UX. In Gmoccapy:</p>
<p><ul>
<li>If you edit a G-code program, save it, and then try to return to the main GUI, it asks you if you're sure you want to exit with unsaved changes. Even though you just saved. The problem is that there are too many abstraction layers and the save button has no way to communicate the fact that the text has been saved, either to the textbox or to the GUI.</li>
<li>I have to manually click "home all" to unlock some parts of the GUI even though homing is a no-op on my machine.</li>
<li>"Restart from line" does not reset to 0 after restarting. "Restart from line" is a useful feature that allows you to restart an aborted
program from a line that you deem sensible, without having to manually delete all of the lines that come first. The problem
is that a.) once you have restarted a program from a given line, any time you start a program, it will <i>always</i> start from the line number you last entered, even if the program completely finished and you've opened an entirely new one where carrying over the line number makes no sense, and b.) the starting line number is not displayed anywhere, so you just have to remember to manully reset it to 0.</li>
<li>There is no cycle time estimate. UGS Platform has a really simple cycle time estimate based on the assumption that every
line of G-code takes the same amount of time to execute. This is fine and useful enough, but Gmoccapy just has nothing.</li>
</ul></p>
<p>I looked at fixing some of this, but the code running on my PC seems to be significantly different to
the code on github, so I guess improvements are being made, and my problem is just that the latest release
is quite old.</p>
<p><a href="https://github.com/kcjengr/probe_basic">Probe_basic</a> looks to be a really nice GUI for LinuxCNC, and even
has a "conversational" interface where you can for example ask it to do simple facing operations without having to
create a G-code program yourself. Unfortunately it requires a display of exactly 1920x1080 pixels. The display I'm using
is only 1024x768 so it doesn't fit. I tried a (very bad) spare 1920x1200 display that I have, but Probe_basic seemed to
scale itself
to fit the 1200 pixel axis instead of the 1920 pixel one, so some of the horizontal space was hanging off the edge of the
screen. I gave up in the end and reverted to Gmoccapy and the 1024x768 screen.</p>
<p><h2>Jog pendant</h2></p>
<p>Before starting a program, you need to set the coordinate system so that you machine material out of your work
piece, instead of the air or the vice. This involves manually "jogging" the tool around to find a reference position
and then setting the coordinate system from there. Unfortunately my computer is the other side of an
opaque laundry basket, so when I can reach the keyboard I can't see where the tool is.</p>
<p>For this reason I have made a "jog pendant" that I can hold while standing closer to the machine.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3859"><img src="https://img.incoherency.co.uk/3859/thumb"></a></p>
<p>It is just a 9-key macro keypad, inside a 3d-printed case. Pressing "Step" sends an "i" keypress which is what Gmoccapy
uses to change the step size. Pressing "X left" sends a left arrow keypress, which moves in the negative X direction,
and so on. "Rapid" is a shift key. Holding shift makes Gmoccapy jog at full rapid speed instead of the configured jog speed.</p>
<p><h2>Making chips</h2></p>
<p>After I first got the motor wired up, I clamped down a piece of aluminium and ran an end mill back and forth
just to get a feel for it.</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/vphhKGTFHvc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>(I knew the workholding was poor, I just didn't have anything better available.)</p>
<p>I was not very impressed with the power of the motor! It kept stalling on relatively shallow cuts in a relatively
soft material. At first I thought I was definitely going to have to get a better motor, but I think my main problems in
that video were that the drawbar was loose (you can hear it rattling), the workholding was inadequate, the spindle speed was
too low, and the cutting tool was blunt. It works a lot better now that I've fixed those problems.</p>
<p>The first actual G-code I ran was to make some shapes out of a piece of aluminium:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3890"><img src="https://img.incoherency.co.uk/3890/thumb"></a></p>
<p>You can see there are some ridges in it. These are partly caused by
loose Z-axis gibs, and partly caused by the head being out of tram (i.e. not perpendicular to the table in every direction).
I have since tightened the gibs but still need to work on tramming.</p>
<p>For my next trick I thought it might be fun to create a <a href="https://journeymans-workshop.uk/toolclamps.php">toolmaker's
clamp</a>, like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3886"><img src="https://img.incoherency.co.uk/3886/thumb"></a></p>
<p>I didn't have a suitable piece of square steel, so I used round bar instead. This is not a bad thing as it gives
me good practice at using the machine to create the shapes I desire. I made this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3887"><img src="https://img.incoherency.co.uk/3887/thumb"></a></p>
<p>The surface finish is <i>OK</i>, and I'm really pleased that I can now machine steel parts.
But there are a number of notable problems here. There is still a step in the top
surface from the machine being out of tram. The finish on the sides is quite rough because my finishing cut
chattered quite badly due (I think) to backlash in the X and Y axes. There were a few false starts while I was
getting my toolpath sorted out which led to a few chunks taken out of the end:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3888"><img src="https://img.incoherency.co.uk/3888/thumb"></a></p>
<p>But mainly I am foolish and drilled the holes in the wrong axis! So this is now completely useless. Oh well. I'll
have another go once I've sorted out the backlash and got the machine back together.</p>
<p>The holes are also not centred properly. This is because I had the steel sitting on parallels in the vice, and I wanted
to avoid drilling into the parallels, so I drilled the holes by hand. This seems like a problem I'm likely to
encounter a lot, so I
need to come up with a solution eventually. Maybe I'd just drill the holes most of the way through on the
milling machine, and then finish them up by hand?</p>
<p>Halfway through making this part my nice new sharp end mills arrived, and they are a big improvement. I can
see on the spindle load meter that the load for the same cut is much lower, which also implies I can take heavier cuts,
and the surface finish is visibly better on the parts that were cut with the new end mill.</p>
<p><h2>Backlash</h2></p>
<p>I found that the Y axis backlash was caused by the screws holding the ballnut to the carriage being loose. They are only
phillips head screws which I can't tighten satisfactorily, so I have replaced them with allen bolts now. I had to
order the bolts, but the delivery crossed the Jubilee weekend so the wait was annoyingly long. It was tempting to reinstall it
with the original screws, but I know I'd have to take it apart again and getting it this far apart is a lot of work
so I'd rather not have to do it again. But anyway I think that problem should be solved now.</p>
<p>There was also a small amount of X axis backlash. I found that there were plastic spacers in between the ballnut and
the holes that it seemingly bolts on to. Originally I was just going to throw the plastic spacers away, but when I came to reinstall
the ballnut I found that the holes don't line up. I also found that the screws holding the ballnut on were M5 while the
holes are only M4! How did this work??</p>
<p>Some head-scratching later, I realised that the bolts were only threading into the plastic "spacers" and
pushing against the surface with the M4 holes, to push the ballnut against an opposing surface, and this is how
the ballnut was attached. What a bodge! This is what happens if you buy unfinished projects on eBay.</p>
<p>Ideally I would drill new holes near the M4 holes and tap them to M5, but unfortunately the required hole location
overlaps the existing holes so it would be very difficult to drill and tap. I also looked at widening the holes
in the ballnut so that I could get M4 screws to line up with the M4 holes, but the ballnut seems to be made of incredibly
hard steel and it blunted both of the drill bits that I tried to use.</p>
<p>So my current plan is
to replace the 2 plastic spacers with an aluminium one that spans both holes. With an aluminium spacer I will be able to
do it up tighter and hopefully it won't come loose. Again these screws had phillips heads so I want to replace them with
allen bolts, but I didn't have any long enough in M5 so I'm again stuck on waiting for delivery of bolts.</p>
<p><h2>Flood coolant</h2></p>
<p>I have made a bit of progress on getting flood coolant set up. The main impetus for this is that I was previously
manually dripping oil onto the steel, and this makes very oily and sticky chips that are difficult to clean up.</p>
<p>I bought "Sabre Sol 2B" on eBay. I chose this coolant because it is available in 1 litre bottles. Most water soluble
coolants seem to come in enormous quantities. The instructions say to dilute it with water somewhere from 5% to 10%
depending on whether you're milling or drilling. Since I'm doing both I just guessed at a concentration somewhere
in between.</p>
<p>My main concerns with the coolant are whether it will rust the precision surfaces on the machine, and whether it will
short out any electronics it comes into contact with. I stuck my multimeter probes in it (on the 2 Megaohm setting) and
didn't manage to measure any conductivity at all unless the probes were touching each other. So I guess it's
non-conductive enough? I will not deliberately submerge my connectors in it, but I think getting it splashed on them
won't be a problem.</p>
<p>I had some drops of coolant sitting on the machine overnight and they seem to have evaporated without leaving
any rust behind, so that's looking like a winner too. I expect it's designed not to cause rust, but it feels very odd
to deliberately spray 90% water onto steel surfaces that you care about.</p>
<p>Here's a video showing my coolant system as it stands at the moment:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/Imqo0-3nKPw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>The big problem is that it pumps much faster than it drains, so if it were running continuously it would flood the tub
and run the pump dry. So I need a bigger drain hole.</p>
<p>The pump I got was <a href="https://www.amazon.co.uk/gp/product/B07V4DRCDD">this one on Amazon</a>. The Amazon listing
says it can pump 2000 litres per hour and lift water 15 feet, but the markings on the pump only say 1.5 metres.
Either way it seems more than adequate for my use case.</p>
<p><h2>Fly cutter</h2></p>
<p>Once I've successfully made a toolmaker's clamp, I think my next milling project will be a fly cutter.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3889"><img src="https://img.incoherency.co.uk/3889/thumb"></a></p>
<p>This is basically like a lathe tool, except it mounts in the spindle of the milling machine and spins around. The
cutting point scribes a much larger radius than a normal end mill, and it is supposed to give a superior surface finish
compared to machining lots of parallel lines with a normal end mill.</p>
<p>The first thing I would do with the fly cutter is re-cut the top surface of my vice jaws to fix a previous blunder...
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/mini-mill-20220609.html</link>
   <guid>http://incoherency.co.uk/blog/stories/mini-mill-20220609.html</guid>
   <pubDate>Thu, 09 Jun 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>FreeCAD vs SolveSpace</title>
   <description><![CDATA[I've been a happy FreeCAD user for about 5 years. Occasionally I
read comments on Hacker News from people who are raving about SolveSpace.
I have briefly looked at SolveSpace before and didn't really get it. It seemed so obviously inferior as not to
be worth looking at. I assumed that all the SolveSpace users were just not willing to put in the work to
understand FreeCAD, and they only thought SolveSpace was good because they didn't know how good FreeCAD is.
But it occurred to me that I was doing exactly the same thing to SolveSpace: I assumed it was worse than
FreeCAD mainly because I couldn't be bothered to put in the work to understand it.
So this evening I finally gave it a proper try and noted down my observations.]]></description>
   <content:encoded><![CDATA[<p>I've been a happy <a href="https://www.freecadweb.org/">FreeCAD</a> user for about 5 years. Occasionally I
read comments on Hacker News from people who are raving about <a href="https://solvespace.com/">SolveSpace</a>.
I have briefly looked at SolveSpace before and didn't really get it. It seemed so obviously inferior as not to
be worth looking at. I assumed that all the SolveSpace users were just not willing to put in the work to
understand FreeCAD, and they only thought SolveSpace was good because they didn't know how good FreeCAD is.
But it occurred to me that I was doing exactly the same thing to SolveSpace: I assumed it was worse than
FreeCAD mainly because I couldn't be bothered to put in the work to understand it.
So this evening I finally gave it a proper try and noted down my observations.</p>
<p>Obviously, 5 years of experience in FreeCAD compared to about 3 hours in SolveSpace is not a fair comparison. Also: I love
FreeCAD. Like... a lot (call it Stockholm Syndrome if you want). Please
bear that bias in mind while reading. I also think 3 hours is just
enough time to run into loads of things that I <i>can't</i> do in SolveSpace, but not enough time to discover great new things
that I couldn't do in FreeCAD. Most of this post is from the perspective of "what's different in SolveSpace compared to FreeCAD?".
If you're a happy SolveSpace user and you think I got something wrong, please correct me!</p>
<p>Whether you're using FreeCAD or SolveSpace, you should definitely run an up-to-date version. The version available in apt
is very out of date in both cases. For FreeCAD I recommend <a href="https://github.com/FreeCAD/FreeCAD-Bundle/releases/tag/weekly-builds">the latest weekly build AppImage</a> (<b>not</b> the latest stable on the website, that one is also woefully out of date). For SolveSpace I
recommend the <a href="https://snapcraft.io/solvespace">solvespace snap package</a>.</p>
<p><h2>Overall workflow</h2></p>
<p>I mostly use the "Part Design" workflow in FreeCAD (distinct from "Part", just to make things easy to understand). The workflow
in SolveSpace is almost exactly the same as Part Design, so I found it very easy to get started, after watching
<a href="https://www.youtube.com/watch?v=WlEHUJhgBuU">a 9-minute video</a> of operating the user interface. Most of it drops straight into
slots in my brain that already exist for Part Design.</p>
<p>The black background colour for the UI in SolveSpace is an unusual choice.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3847"><img src="https://img.incoherency.co.uk/3847/thumb"></a></p>
<p>It makes the software feel much more foreign and confusing
than it really is. But it also contributes to the general "feel" of the program. You feel like you're working more closely with the
geometry of the part than you do in FreeCAD. So I don't know if the weird colour scheme is a good thing or a bad thing overall.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3848"><img src="https://img.incoherency.co.uk/3848/thumb"></a></p>
<p><h3>What's better in SolveSpace?</h3></p>
<p>The SolveSpace workflow is more cohesive in a way that is hard to give a feel for if you don't actually try it out.</p>
<p>In FreeCAD you have one view for creating a sketch,
and then when you're done with the sketch you close it and you have a separate view for turning the 2D sketch into a 3D feature.
In SolveSpace it's all the same view. In particular this means that defining things like the length of an extrusion or the angle
of a revolution are done using exactly the same constraint solver as the sketch uses! This was a revelation to me.</p>
<p>In FreeCAD you
have this amazing constraint solver available in 2D for your sketches, but then when you want to turn them 3D, it all disappears and
you have to choose between a simple length, or a pad up to an existing face, or a pad up to an existing face with a custom offset,
and so on. The available options are quite extensive, but not exhaustive, and are wholly unnecessary in SolveSpace.
In SolveSpace, the extrusion
is just dimensioned using constraints. You can very easily do complicated things to decide the length of an extrusion without
doing any maths in your head. Just define construction lines in 3D space and constrain the extrusion to meet your construction lines.
Easy peasy. This is very powerful and I wish FreeCAD worked this way.</p>
<p>I also like that the SolveSpace "shown" checkbox can make many "groups" visible at the same time. A "group" in SolveSpace is roughly
the same as any single item in the project tree in FreeCAD.
If you turn several of them on at once (the default behaviour is to
show them <i>all</i> at all times) then you get to see all of the elements in every sketch at once (but you only see the constraints of the
active group):</p>
<p><a class="img" href="https://img.incoherency.co.uk/3838"><img src="https://img.incoherency.co.uk/3838/thumb"></a></p>
<p>In particular, these can then be used to reference other geometry to, to create new sketches, and so on. There's no need to create datum
planes or datum lines like you do in FreeCAD. You can just create construction lines directly in 3D space, referencing any geometry
in any "group". I think this is a big part of what makes SolveSpace fun to use.</p>
<p><h3>What's worse in SolveSpace?</h3></p>
<p><h4>Fillet/chamfer</h4></p>
<p>There are no fillet/chamfer tools in SolveSpace. This was a big disappointment. The best way to create a fillet or chamfer is to model
it in the 2D sketch. This obviously doesn't work for the edges of the flat faces created by the extrusion. In those cases you need to create a
new sketch and cut it away from the edges of the extrusion. You also need to make sure that the edges of your sketch do not exactly
line up with the edges of the existing part, otherwise SolveSpace gets confused and forgets to fill in some of the adjacent faces,
which leaves holes in your part:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3834"><img src="https://img.incoherency.co.uk/3834/thumb"></a></p>
<p>The solution is to space the bounds of the fillet away from the existing part geometry:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3835"><img src="https://img.incoherency.co.uk/3835/thumb"></a></p>
<p>This whole method is annoying and time-consuming and will result in SolveSpace-modelled parts having sharper edges than FreeCAD-modelled
parts with almost 100% probability, because softening the edges is too much trouble.</p>
<p>I'm not saying FreeCAD fillets and chamfers are bug-free! Far from it. Few among us is the FreeCAD user who has not lost an hour's work
when the fillet segfaulted an unsaved project. But with time you do learn what kinds of things are likely to crash the filleting
tool, and mainly you learn to save before applying risky fillets.</p>
<p><h4>Thickness</h4></p>
<p>I don't use the Part Design Thickness operation very often, but when I do it is a big time-saver. It allows you to model things like
an electronics project enclosure as just the outer shape, and then turn it into a hollow part with uniform thickness and 1 open face
with a single click. In SolveSpace I think you'd have to manually model both the external and internal geometry, I'm not aware of
any way to automatically create the uniformly-sized offset.</p>
<p><h4>Rotation</h4></p>
<p>I can't figure out how the 3D rotation works in SolveSpace. There are 2 options (the default one and "turntable") and they are both
equally baffling to me. They both have the peculiar property that you can drag the mouse around in a circle while rotating, and when
the mouse gets back to the start point on the screen, the part will not have returned to the starting orientation. I expect this is the sort of thing
that you get used to with time, but for now rotating the part is very much a guessing game for me. It doesn't work like any 3D mouse
rotation I am familiar with.</p>
<p><h4>Pad direction</h4></p>
<p><strike><p>Normally when you create a Sketch and make a Pad (in FreeCAD) or a Union extrusion (in SolveSpace), it comes "up" out of the sketch,
and towards the direction you were looking at it from, and when you make a Pocket (FreeCAD) or Difference extrusion (SolveSpace) it goes
in the other direction. All very good and sensible.</p>
<p>In FreeCAD if you want your Pad or Pocket to go in the other direction, you tick the box that says "Reversed" when creating the pad.</p>
<p>In SolveSpace if you want your Union or Difference extrusion to go in the other direction, you need to delete the extrusion, delete the sketch,
and start again with
a workplane that faces in the other direction. I hope I'm wrong on this one, because it seems unlikely that there is deliberately
no way to reverse the direction of an extrusion.</p></strike></p>
<p><b>Update:</b> u/henrebotha points out that you can reverse an extrusion just by clicking on the surface and dragging it in the opposite
direction. This is great! It's actually quite intuitive, I don't know why I didn't think to try it. I must have still been stuck in the FreeCAD mindset of
trying to interact with the GUI rather than the part.</p>
<p><h2>Sketches</h2></p>
<p><h3>What's better in SolveSpace?</h3></p>
<p>SolveSpace visually shades the enclosed area of the sketch so that you can see which parts are "positive" and which parts are "negative".
This is good and FreeCAD should copy it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3850"><img src="https://img.incoherency.co.uk/3850/thumb"></a><br>
<small>(It's a dark blue-ish colour on a black background; for some reason it's easier to see in the application than in the screenshot)</small></p>
<p>SolveSpace also helpfully points out where your sketch is non-closed so that you have half a chance of fixing it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3849"><img src="https://img.incoherency.co.uk/3849/thumb"></a></p>
<p>It's very annoying to
spend a long time on a complicated FreeCAD sketch, and then go to create a Pad, only to find that it can't create
the Pad because the sketch is not a closed shape. <strike>You then have to manually check every vertex in the sketch to find out which ones
aren't connected properly, only to find that 2 points that looked the same are actually 0.01mm apart.</strike></p>
<p><b>Update:</b> u/strange_bike_guy points out that FreeCAD has a "validate sketch" tool that can automatically find missing coincidences
within a given tolerance.</p>
<p>Once you've created a sketch in 3D, I love that you can click and drag the unconstrained face and move it around in 3D space. I grant
that this is usually not particularly useful, because you'll usually want to add a constraint to the length anyway, but it adds to
SolveSpace's feeling of a direct connection to the part geometry. In FreeCAD you just have a text box to type a length into and absolutely
no chance of manually dragging the extrusion around.</p>
<p>In FreeCAD if you want a sketch to reference some geometry that already exists on the part, you need to use the "external geometry" tool
to bring it into the sketch. This never really occurred to me as an unusual thing to have to do, but in SolveSpace that tool just... doesn't
exist. You just don't have to do it. All of the geometry is already available to use, you don't have to do anything weird to bring it in.
This just seems obviously better. I'm not sure why FreeCAD isn't this way.</p>
<p><h3>What's worse in SolveSpace?</h3></p>
<p><h4>Sketch attachment</h4></p>
<p>In FreeCAD you can create a sketch on any existing flat face of the part very easily. Just select the face and then click the "create sketch"
button. In SolveSpace, even though flat faces are highlighted in a weird yellow mesh when you hover over them, selecting a face
and then trying to create a "workplane" based on it does not work.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3841"><img src="https://img.incoherency.co.uk/3841/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3842"><img src="https://img.incoherency.co.uk/3842/thumb"></a></p>
<p>Even though if you select a single <i>point</i>, creating a workplane
based on the point works fine. Doesn't a face describe a plane better than a point does? I don't really understand the thinking there.
What you have to do instead is select 2 of the lines that form the edges of the face, then a point somewhere on the face, and then create
the workplane. It works fine but feels over-complicated in the common case of creating a sketch coplanar with an existing face. I also
don't see what the point adds over the 2 lines. Don't 2 coplanar lines describe a plane on their own? It's also difficult to make a workplane
on a circular face, because you don't have any straight lines to use.</p>
<p>In FreeCAD once you've created a sketch on a face, you still have the option to adjust the attachment position of the sketch so that it is offset
from the face you attached it to. I don't do this particularly frequently, but when I do it is a big time-saver compared to
setting up a datum plane.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3843"><img src="https://img.incoherency.co.uk/3843/thumb"></a></p>
<p>In SolveSpace, you have
to manually set up some construction geometry that is offset from the face and then create your workplane on your construction geometry.
It works, and it's not that much more work than just creating a workplane off existing geometry. But what is much worse in SolveSpace
is that once you've created the workplane, if you didn't have the foresight to add an offset in the first place, you can't add an offset at all. If you change your mind about where you want the sketch, you
need to delete it and start all over again. (And, actually, I'm not sure how this works if you change your mind about where you want a
sketch that is several steps back in the Property Browser; do you need to remake everything that came later? I hope not. Probably someone
who knows more about SolveSpace than me would know a way to adjust a sketch attachment without breaking everything that came later).</p>
<p><h4>Multiple constraints</h4></p>
<p>In FreeCAD you can select any number of lines and set an equality constraint on their lengths. Or you can select any number of points
and put a vertical constraint on them to make them all lie in a vertical line. In SolveSpace, these constraints can only operate on 2
lines or 2 points respectively. This means when you have a lot of lines to make equal, or a lot of points to make vertical, it takes
twice as many clicks in SolveSpace as it does in FreeCAD.</p>
<p><h4>Redundant constraints</h4></p>
<p>In FreeCAD there is an option for "auto remove redundants".</p>
<p><a class="img" href="https://img.incoherency.co.uk/3844"><img src="https://img.incoherency.co.uk/3844/thumb"></a></p>
<p>This allows you, for example, to set points coincident with each other,
and if the points already have some constraint that meant they were already coincident in one axis, that constraint can be automatically removed from
one of the points to avoid over-constraining the sketch. SolveSpace doesn't appear to have any workaround for this. The closest thing it
has is "ignore redundant constraints", but see the "Bugs" section below for why this isn't satisfactory. The best way to avoid this is to
try to remember to constrain points to lines rather than to other points. And when you know you're going to make 2 circles symmetrical
about the origin, for example, remember to place one circle on the X axis, and remember <i>not</i> to place the other circle on the X axis,
otherwise after you add a symmetry constraint across the Y axis, you'll have 2 separate constraints putting the circles on the X axis, which
makes the sketch over-constrained. Just a bit more forethought required in SolveSpace than in FreeCAD.</p>
<p><h4>Unconstrained elements</h4></p>
<p>In FreeCAD, unconstrained elements in sketches are shown in a different colour to constrained elements (white instead of light green).</p>
<p><a class="img" href="https://img.incoherency.co.uk/3845"><img src="https://img.incoherency.co.uk/3845/thumb"></a></p>
<p>This makes it relatively
easy to locate the unconstrained parts. SolveSpace doesn't have any obvious way to point you towards the unconstrained elements, you
just have to think about it and find them on your own.</p>
<p><h4>Symmetry across a point</h4></p>
<p>SolveSpace can't do a symmetry constraint across a point. It can only make 2 points symmetrical across a line. Making 2 points symmetrical
across a point is the fastest way to centre a rectangle on the origin, and maybe 50% of my parts in FreeCAD start this way. In SolveSpace
you'd have to make the top edge symmetrical across the Y axis, and the left edge symmetrical across the X axis. (And then you'd have
to manually remove the vertical and horizontal constraints on the rectangle, else it's over-constrainted). It just takes more clicks in
SolveSpace.</p>
<p><h4>Cross-section view</h4></p>
<p>In FreeCAD's Sketcher workbench there is a button called "View Section" that turns the view into a cross-section of the part along the
sketch plane.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3846"><img src="https://img.incoherency.co.uk/3846/thumb"></a></p>
<p>That means every feature on the part that would sit between the "camera" and the sketch plane is hidden, so that the sketch
is unobscured. This is a very useful feature. I couldn't find anything equivalent in SolveSpace, which means if you work on a sketch that
intersects the existing solid, you're going to struggle. The closest thing I could find was "draw occluded lines" so that you
can see the lines on your sketch even though they're not on top. But this can presumably get very cluttered in a complicated part.</p>
<p><h2>Assembly</h2></p>
<p>FreeCAD has a <i>lot</i> of different assembly-related workbenches. I don't use any of them. I think there are too many options and
they all work too differently, and there is a sort of <a href="https://en.wikipedia.org/wiki/The_Paradox_of_Choice">paradox of choice</a>
where I can't work out what I should be using, and I work around it by manually positioning and rotating separate bodies using the
property editor instead.</p>
<p>SolveSpace seems to have a simple assembly system built-in. I have not used it yet, but it seems so much simpler that if I do use SolveSpace
for a non-trivial project then I will almost certainly use the assembly system.</p>
<p><h2>CAM</h2></p>
<p>CAM seems to be missing from SolveSpace. I expect even if you really liked SolveSpace and hated FreeCAD, the best way to do CAM would
be to model your part in SolveSpace, and then load it in FreeCAD to use the Path workbench. (Unless you want to do 3D CAM,
in which case you should definitely try <a href="https://incoherency.co.uk/blog/stories/meshmill.html">Meshmill</a> instead!).</p>
<p>There <i>are</i> some CAM-related options in the "configuration" window (window? tab? zone?), namely "cutter radius offset" and
"exported g code parameters" but I couldn't find anything in the user interface that would actually generate any G-code. I'm not
sure if it is not implemented yet or just too hard for me to find. But I didn't look very hard, and besides, even if it is there, the fact
that "cutter radius offset" is a <i>global option</i> does not suggest very advanced toolpath generation.</p>
<p><h2>Bugs</h2></p>
<p><h4>FreeCAD bugs</h4></p>
<p>FreeCAD has plenty of bugs of its own. In FreeCAD, bugs frequently segfault the application. If you try to do anything complicated in
FreeCAD, it is going to segfault on you. That's just part of the experience. Remember to save frequently. When
it segfaults, just reload FreeCAD and try the same thing again. Most of the time it will work. If you have found something that reliably
segfaults FreeCAD then you just need to find a different way to do what you're trying to do. But segfaults are just part of life when
you use FreeCAD. The first time it happens it feels like a complete impediment to getting any work done, but eventually you realise it's
just a low percentage drain on productivity and not a big deal. I'd rather have a Russian Roulette filleting tool
than no filleting tool at all! And I would definitely say stability improves with each new release I download.</p>
<p>FreeCAD has an automatic project recovery tool that is meant to restore your unsaved work after a crash. I'm pretty sure it doesn't work.
It's some sort of complicated cruel joke. The only time it ever restores what you were working on to the state you wanted is when it was a test part that you didn't need.
But it doesn't matter. Just learn to save your work!</p>
<p>I didn't have a single segfault from SolveSpace, which is good. In fact I didn't find any bugs that would trash your work without warning.</p>
<p><h4>Property Browser window going all black</h4></p>
<p>I found that the Property Browser window sometimes goes completely black and I need to waggle the mouse over it to get it to redraw. I don't
know why.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3839"><img src="https://img.incoherency.co.uk/3839/thumb"></a></p>
<p><h4>Unwanted open faces</h4></p>
<p>I consider the thing where it makes open faces if you try to make a fillet that is exactly coincident with existing geometry to be a bug.
But let's say you don't! Let's say you <i>want</i> open faces when you try to make a fillet coincident with existing geometry.
Even then, surely <i>this</i> is a bug:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3836"><img src="https://img.incoherency.co.uk/3836/thumb"></a></p>
<p>I tried to create a cylinder that partly passed through open space and partly joined to an existing solid, and it just didn't work at all.
It left some open faces for no reason that I can discern. I have come across this sort of thing in FreeCAD, but only a handful of times ever,
and always when doing something very weird. In SolveSpace it seems to happen a lot. I expect this will get better in time.</p>
<p><h4>"Ignore redundant constraints"</h4></p>
<p>If you enable "ignore redundant constraints" on a sketch, then SolveSpace always thinks that sketch is completely constrained.
This is a real shame because I really like the way that SolveSpace shows the number of degrees of freedom of each "group" in the Property
Browser. In FreeCAD, if you want to know the degrees of freedom of a sketch, you have to open up the sketch to find out. If you want to
check whether all sketches are fully-constrained, you need to open every sketch separately to check.
In SolveSpace you can just eyeball the list of groups for any that don't say "ok" in the "dof" column.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3840"><img src="https://img.incoherency.co.uk/3840/thumb"></a></p>
<p><h4>"Draw occluded lines"</h4></p>
<p>There's a button called "draw occluded lines" which seems to have 3 modes. In one mode, occluded geometry is not shown at all. In another
mode, occluded lines are shown but occluded points are hidden. In the final mode, occluded lines and points are both shown. When you
click the button, it seems to switch from the currently active mode to one of the other 2 modes chosen at random. If there is logic to
the choice, I was not able to fathom it. I'm not sure whether this is a bug or whether the logic is too complicated for me to understand.
It's easy enough to work around though: just keep clicking the button until you get what you want.</p>
<p><h2>Verdict</h2></p>
<p>SolveSpace is fun to use in a hard-to-describe way that FreeCAD is not. It is also much more stable (i.e. it doesn't segfault).
It is also much more immature than FreeCAD, and much less feature-complete. Overall I think FreeCAD is a more productive CAD
program, mainly just because it can do fillets and chamfers, and you encounter open faces much less frequently, but also because
of the "long tail" of little things that can be done in fewer clicks in FreeCAD.</p>
<p>That said, I found SolveSpace much faster to become productive in than FreeCAD was.
Part of this is probably because I have already spent the time
to learn the Part Design workflow in FreeCAD, and SolveSpace can piggyback on my learning investment. But I do think SolveSpace is
genuinely easier to learn than FreeCAD. There is just much less <i>there</i> in SolveSpace, so tentatively exploring the UI by clicking
on things and seeing what happens is actually a viable strategy in SolveSpace. Not so much in FreeCAD. FreeCAD seems to have a lot more
things available to click on, without a correspondingly large number of extra features.</p>
<p>If you just want to create parts for 3D printing and you haven't used either SolveSpace or FreeCAD before, start with SolveSpace. If you
want to make parts for CNC, probably start with FreeCAD because you'll probably need FreeCAD anyway when you want to make toolpaths.
If you
use FreeCAD for productivity and you want something different to use for enjoyment, and on small projects, SolveSpace is worth your time.
If you are competent in SolveSpace and you want something more powerful, FreeCAD is worth your time.</p>
<p><h2>Potential easy improvements to SolveSpace</h2></p>
<p>(I don't know if these things are <i>actually</i> easy, but they feel "close to the surface").</p>
<p>It would be cool if hovering over a "group" in the Property Browser highlighted all of the geometry that belongs to that group. In the event that this is ambiguous: let's say it highlights all of the geometry that would disappear if that group were made invisible. I often have trouble
in FreeCAD working out which sketch created a particular feature, if I need to go back and change it. If I'm trying hard then I rename the features that I create so that I can tell what they are, but most of the time I don't bother. Manually toggling visibility of Pad001, Pad002, Pocket001, Pad003, etc., until I work
out which one my feature came from is very time-consuming. It seems like it would be quite easy for SolveSpace to be able to do this with
just a hover in the Property Browser.</p>
<p>Whenever the view needs to reorient, the rotation is animated. The animation is infuriatingly slow. It's probably only a second or so,
but it feels bad. It should be more like 100ms in my opinion.
Most of the time SolveSpace is a perfect servant of the user, always ready to process your
inputs as fast as you can provide them. But that is broken for a little while whenever it rotates into a new position. I looked for an option
to make the animation
faster, but I couldn't find one. Animated rotations are useful because they help you stay mentally oriented with the part, but I think I would
rather have no animated rotations at all than animations that are this slow. FreeCAD also has animated rotations but they are optional
and you can change how long they take in the settings. SolveSpace should just make this configurable. I mostly ran into this problem after
I accidentally rotated a part while editing a sketch, and then hit "W" to put the view back to the workplane, but then I had to wait
for the animation to be done even though I already knew exactly how the workplane was oriented to the part.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/freecad-vs-solvespace.html</link>
   <guid>http://incoherency.co.uk/blog/stories/freecad-vs-solvespace.html</guid>
   <pubDate>Tue, 24 May 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>CNC milling machine project</title>
   <description><![CDATA[I recently picked up an unfinished CNC milling machine project on eBay.
All the mechanical work is done, and almost all of the electronics is
supplied, it's mostly just wiring and software still to do, which for me are the
easiest parts.]]></description>
   <content:encoded><![CDATA[<p>I recently picked up an unfinished CNC milling machine project on eBay.
All the mechanical work is done, and almost all of the electronics is
supplied, it's mostly just wiring and software still to do, which for me are the
easiest parts.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3821"><img src="https://img.incoherency.co.uk/3821/thumb"></a></p>
<p>It's a "mini mill". I don't know what company in China actually makes these, but they're
a small manual milling machine sold under various brand names. They look like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3823"><img src="https://img.incoherency.co.uk/3823/thumb"></a></p>
<p>The man I bought it
from claims to have spent &pound;1000 on just the machine. There are 6 motors and drivers (3 axes,
plus 2 rotary axes not yet built, plus a spare), which
come
to &pound;600 on AliExpress just by themselves, and the purchase also included the pictured hotel-laundry-basket enclosure,
a very sturdy (and heavy) welded steel stand, a PC, a touchscreen for the PC, and other assorted
stuff that all adds up (2x DC power supplies, parallel port breakout board, electrical cabinet,
ER32 collet set, ballscrews, belts, pulleys). Not to mention the time and materials that went into
making all the parts for mounting the motors. I think &pound;500 for the lot is a steal!</p>
<p>However I did have to drive to Bingley to collect it, which is a 10-hour round trip,
so you can add on another &pound;100 just in fuel.</p>
<p>I've been spending a lot of time working on <a href="https://incoherency.co.uk/blog/stories/meshmill.html">Meshmill</a>
recently so haven't done much with the milling machine project, but today I
<a href="https://www.youtube.com/watch?v=cjtz2GGQp_o">got all 3 axes moving for the first time</a>.</p>
<p><h2>LinuxCNC</h2></p>
<p>The previous owner had set the control box up with a parallel port break-out board, and supplied
a suitable PC for Mach 3 to control it over a parallel port. I'm not interested in Mach 3
because I like freedom, so
I thought the easy route would be to use LinuxCNC to drive the parallel port,
rather than install Grbl on an Arduino <a href="https://incoherency.co.uk/blog/stories/6040-cnc-grbl-arduino.html">like on my router</a>.</p>
<p>So far I have had quite a lot of trouble with LinuxCNC, to the point that I am surprised anyone bothers with it. It
is <i>a lot</i> more complicated than Grbl, for almost no benefit.
I grant that some of
the complication makes it more flexible, like the hardware abstraction layer, and all the different
options for GUIs, and the ability to swap in different kinematics modules for different types of
machine.</p>
<p>But a lot of the complexity is a result of trying to use PCs to do real-time electronics. For example,
you have to make sure the parallel port is set to the correct mode in the BIOS configuration, otherwise
it only works in one direction. You need to run a latency test to find out how much jitter can be expected
from process scheduling so that you can set the main loop frequency correctly. The main loop frequency sets your maximum
step rate, which is shockingly low compared to Grbl on an Arduino.</p>
<p>And it turns out that there is some problem with the GPU in the PC that I am using, so I have had to
disable the <tt>glx</tt> kernel module otherwise the computer locks up every few minutes.
It also turns out that most of the LinuxCNC GUIs require
OpenGL, so most of them don't work. I'm using Qtaxis currently, which works fine but is strictly
less convenient than UGS Platform, which is what I use with Grbl (most notably, jogging the axes takes more clicks, and manually
setting the current position requires typing <tt>G92</tt> commands at the console instead of editing
the number in the DRO). I'll probably make my own Qtvcp GUI if I don't come up with something better.</p>
<p>But for now I'm persisting with LinuxCNC. Maybe I'll see the light eventually.</p>
<p><h2>Servo drives</h2></p>
<p>Rather than traditional stepper motors, this machine came with Leadshine "hybrid servo motors". They are controlled just
like stepper motors (you give step & direction signals to the driver), but I gather that the motor internally
works like some sort of cross between a true servo motor and a stepper motor with an encoder on it. I don't
completely understand how it differs from a true servo motor, but they're variously called "hybrid servos"
and "easy servos" rather than just "servos" so I'm guessing there is some important difference.</p>
<p>When you crash a machine with normal stepper motors, the driver has no way to know, so the motor loses steps
and the job carries on
and the work piece gets destroyed and there is no way for the control software to do anything about it.</p>
<p>With these Leadshine motors, the driver continuously monitors the position of the motor and if it differs from the commanded
input, it tries to correct it. If it is unsuccessful, and the following error gets too large, then the driver cuts power to
the motor and goes into an alarm state. There is an alarm output from the driver which can be connected to
the control software so that you can know something bad has happened, stop moving the other axes, and maybe not
cause as much damage.</p>
<p>So far so good.</p>
<p>But once the driver has got into the alarm state, I'm not actually sure if there is any way to get it <i>out</i>
of the alarm state short of switching it off and on again. I tried toggling the enable pin but it seems to do
nothing once the alarm state is active. I could add a relay to the power input so that LinuxCNC has
a way to power cycle the drivers, but that seems like a hassle. I'll probably just manually switch the power
off and on again if that's the only way to clear the alarm. I don't expect to have to do it very frequently
anyway.</p>
<p><h2>Spindle motor</h2></p>
<p>The spindle motor is (I think) 500 W or 750 W. This seems very low. My router has a 1500 W spindle motor,
and the router is a lot less rigid than the mini mill, so I would expect the mini mill should be able to
put much more power into a cut than the router can.</p>
<p>Another one of my weird eBay "bargains" recently was a 2200 W water-cooled spindle motor that leaks. I think it would
be straightforward enough to fix the leak and fit it to the mini mill, but I'm not sure whether it would be
a good idea. The 2200 W motor spins up to 24000 rpm, which is fine for a router but way too much for more
traditional milling. It's possible that reducing the speed of the 2200 W motor from 24000 rpm to something more suitable
would put it at a point on the torque curve where it is producing <i>less</i> power than the original spindle
motor. So I'm not sure exactly what to do about that. For now the path of least resistance is just to wire up
the motor that already fits, rather than make a mount for the other one.</p>
<p>When I got the machine, the spindle motor was not fitted, which confused me because everything else
about the mechanical assembly seemed complete. I have now worked out why the motor was not fitted.</p>
<p>The mounting plate for the spindle motor is a beautifully-machined part, but it all lines up
so that you can have any 2 of:</p>
<p><ul>
<li>belt installed</li>
<li>motor bolted to mounting plate</li>
<li>mounting plate bolted to machine</li>
</ul></p>
<p>Getting all 3 at once seems impossible. I'm going to keep working at it though. There are lots of possibilities for the order
of operations (motor on plate first, or plate on machine first? belt on before or after plate?), and maybe
if I switch to hex head bolts instead of allen bolts I'll have more clearance to get the spanner in. Maybe this puzzle has a solution after all!
Especially if I allow myself to skip out a couple of the less-important-looking bolts.</p>
<p><h2>Emergency stop</h2></p>
<p>The emergency stop switch provides a signal to the control software (boooo! The emergency stop should always cut power
to the machine, not speak to the software). I set it up using the Stepconf tool in LinuxCNC, but found that it
wasn't working at all. LinuxCNC didn't recognise that the switch was being pressed. (Which is precisely why the emergency
stop needs to cut power on its own, not speak to software).</p>
<p>I eventually found out that the parallel port breakout board I'm using requires the 12-24V power supply to be present
<i>as well as</i> the 5V supply if you want inputs to work.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3822"><img src="https://img.incoherency.co.uk/3822/thumb"></a></p>
<p>I had assumed that the 12-24V supply was only there to get 10V for the spindle speed output, but apparently not.
It is even more confusing because the <i>outputs</i> work just fine with only the 5V supply connected.
So if you're having trouble getting LinuxCNC to read inputs from the parallel port breakout board: make sure you
have the 12-24V supply connected as well as the 5V one.</p>
<p><h2>Limit switches</h2></p>
<p>The machine doesn't have any limit switches installed. The eBay listing showed proximity sensors in one of the pictures,
presumably intended for use as limit switches, but when I got everything home I found that these had not been packed in
any of the boxes.</p>
<p>I don't think it's a big deal to be without limit switches. I don't have any limit switches on my router and that seems
fine. You need to set the origin of the coordinate system before you start a job whether you have limit switches or not.
In the absence of an automatic tool changer or tool height setter, I don't think there's any advantage to
having the concept of a global coordinate system, so I probably won't bother fitting any limit siwtches.</p>
<p>However LinuxCNC does seem to be more of a stickler for global coordinates than Grbl is. If you try to drive the
machine outside the software-configured bounding box then it causes an error instead of just doing what you asked.
Probably the solution is to set the bounding box really large so that LinuxCNC always thinks it's inside it.</p>
<p><h2>Enclosure</h2></p>
<p>The enclosure is made out of a plastic hotel laundry basket. It seems like a really good idea. It's a lot less work than
fabricating a custom metal enclosure, easier to keep watertight, and surprisingly sturdy. The door/window is a plastic panel
that drops in from the top and slides inside some rails. It's a bit of a wiggle to fit the panel between
my garage ceiling and the enclosure, to put it on or take it off. I don't know if this will prove to be annoying. I
may put it on hinges if it is.</p>
<p><h2>Coolant</h2></p>
<p>Once I have the machine properly working and installed in its enclosure, I think I might like to add a flood coolant
setup. I would do this with an aquarium pump. I would probably want to make sure the enclosure is slightly out-of-level
so that all the liquid pools up in one corner, and then drill a hole in that corner to let the coolant drip back
into the reservoir for recirculation.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/cnc-mini-mill.html</link>
   <guid>http://incoherency.co.uk/blog/stories/cnc-mini-mill.html</guid>
   <pubDate>Sat, 07 May 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Meshmill: open source 3D CAM</title>
   <description><![CDATA[For the last couple of weeks I've been working on Meshmill.
It's a new 3D CAM program for Linux.]]></description>
   <content:encoded><![CDATA[<p>For the last couple of weeks I've been working on <a href="https://github.com/jes/meshmill">Meshmill</a>.
It's a new 3D CAM program for Linux.</p>
<p>If you run Linux (on x86_64) and want to try it out, you can download the AppImage from <a href="https://github.com/jes/meshmill">the Github repository</a>.</p>
<p><a class="btn btn-primary" href="https://github.com/jes/meshmill/releases/tag/v0.1.1">Download the latest Meshmill AppImage</a></p>
<p>If you try it out (successfully or otherwise!) please let me know how you get on, what you struggled with, etc. And I'd love to see pictures of your parts :).</p>
<p>I have filmed an introductory video showing how to use it to make a part:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/lPOzEK2OKvY" frameborder="0" allow="allowfullscreen" allowfullscreen></iframe></p>
<p><h2>What is 3D CAM?</h2></p>
<p>You can machine a lot of parts by machining features at different heights in flat planes. This is called "2.5D" machining, because although
the produced parts are 3-dimensional, all of the tool movements are only in the XY plane, with the Z axis only moving to get into position
before the start of each level. You can only make surfaces that are horizontal or vertical.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3819"><img src="https://img.incoherency.co.uk/3819/thumb"></a><br><small>(From <a href="https://web.archive.org/web/20120301044451/http://www.welsoft.co.uk/machmill/hs20.htm">Welsoft</a>)</small></p>
<p>Most of the parts I make on my CNC machine are made with 2.5D toolpaths generated by FreeCAD.</p>
<p>To make parts that have angled or curved surfaces, you need to move the tool in the Z axis <i>at the same time</i> as the X or Y axis.
This is "3D" machining, and this is what Meshmill is designed for.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3820"><img src="https://img.incoherency.co.uk/3820/thumb"></a><br><small>(From <a href="https://web.archive.org/web/20120301044451/http://www.welsoft.co.uk/machmill/hs20.htm">Welsoft</a>)</small></p>
<p>FreeCAD has some buttons that are supposed to be able to generate 3D toolpaths, but I've never been able to get them to work.
PyCAM makes 3D toolpaths but I always ran into Python errors when trying to run it. BlenderCAM is supposed to be good, but
I only found out it exists after I started working on Meshmill, and although I have used Blender on occasion, I find it
too complicated.</p>
<p><h2>How does it work?</h2></p>
<p>In 2020 <a href="https://incoherency.co.uk/blog/stories/cnc-heightmap-toolpaths.html">I wrote a tool called Pngcam</a> that takes a heightmap as input and produces
G-code as output. It also has another tool that takes an STL model as input and produces a heightmap as output,
so that they can be used together to make G-code from an STL model. Pngcam is a 3D CAM program, but it is inconvenient to use because it is operated from the command line.</p>
<p>Meshmill is an Electron application providing a GUI frontend to Pngcam.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3818"><img src="https://img.incoherency.co.uk/3818/thumb"></a></p>
<p>Since getting the GUI working, I have also finally got around to adding more advanced features to Pngcam, such as ramping
on plunge cuts to reduce tool load, skipping out cuts on the flat top surface of the material, reordering cutting segments
to reduce time wasted on travel moves, and producing an output heightmap showing what the material will look like after
one operation so that it can be used as input for the next operation to stop wasting time machining air.</p>
<p>I've also reimplemented Pngcam in Go, partly for performance reasons, and partly because Go binaries are easier to package in
an AppImage than the Perl scripts were.</p>
<p>(The problem I had with the Perl scripts was that they used GD to handle images, and
GD is an XS module that uses libgd. So I dutifully packaged libgd.so.3, and GD.so, and wrote a wrapper script that mucked
about with <tt>LD_LIBRARY_PATH</tt> to get it to work, and I succeeded. Great success! But then I tried to launch the program
on a different computer, with a different Perl version, and it didn't work, because XS modules are tied to the Perl version
they were built against. So then I worked out how to package a matching Perl installation in the AppImage as well, and I expect that would have
been enough, but it seemed very distasteful, would be very annoying to update, and added about 20 megabytes to the size of the AppImage.)</p>
<p><h2>What's good about it?</h2></p>
<p>Meshmill's primary feature is that it is (intended to be!) easy to use. Importantly, this includes "easy to install": there is
no compiling and no dependencies, you just download the AppImage and run it.</p>
<p>I have found other options for open source 3D toolpath generation very
difficult to get started with, to the point that I have never succeeded in generating a 3D toolpath except with Pngcam and
Meshmill. If you are already using a different open source 3D CAM program: chances are it is better than Meshmill
and you should stick with it. If you haven't had success with other open source 3D CAM, you could try out Meshmill.</p>
<p><h2>What's bad about it?</h2></p>
<p>Despite recent improvements, Pngcam's planning is suboptimal. It still spends more time on travel moves than it could do
if it ordered the cutting segments more intelligently. (Ordering cutting segments optimally requires a Travelling Salesman Solution,
but I'm sure it could reasonably do better than it currently does).</p>
<p>It can generate travel moves that touch the surface of the part, which in combination with the "omit top" setting, can
result in taking small gouges out of the top surface of the part, if the Z axis is zeroed slightly below the top surface.
See my sake set picture below for an example of this.</p>
<p>There are still some very useful features missing from the GUI, primarily:</p>
<p><ul>
<li>some way to generate hold-down tags</li>
<li>a way to rotate the part to more faces than just top and bottom (probably I'd aim to duplicate the PrusaSlicer UX here)</li>
<li>a way to start from a heightmap instead of an STL model</li>
<li>a way to export the "stock" heightmap from one job and import it into another</li>
</ul></p>
<p><h2>My sake set</h2></p>
<p>The first part I have made using Meshmill is this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3816"><img src="https://img.incoherency.co.uk/3816/thumb"></a></p>
<p>It is an insert for a box to hold my <a href="https://en.wikipedia.org/wiki/Sake">sake</a> set (a jug and 4 little drinking cups).</p>
<p>Wanting to make this part is what finally pushed me to make the GUI for Pngcam in the first place, so I'm glad I've now succeeded in
that sense. Hopefully that doesn't mean I've got what I wanted out of Meshmill and will entirely stop working on it now!</p>
<p>I'm going to coat this part in <a href="https://en.wikipedia.org/wiki/Flocking_(texture)">flocking</a> to give it a fabric-ish
texture, and build a box with a lid around the outside.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/meshmill.html</link>
   <guid>http://incoherency.co.uk/blog/stories/meshmill.html</guid>
   <pubDate>Tue, 03 May 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Using the weird rotary axis</title>
   <description><![CDATA[I've been playing with my weird rotary axis for a couple of weeks now.
It's a rotary axis mounted on the gantry, with the rotation of the chuck geared
off a toothed rack on the table.
I've had a few questions about the practicalities of using it, so this is some of
what I've learnt.]]></description>
   <content:encoded><![CDATA[<p>I've been playing with my <a href="https://incoherency.co.uk/blog/stories/cnc-rotary-axis.html">weird rotary axis</a> for a couple of weeks now.
It's a rotary axis mounted on the gantry, with the rotation of the chuck geared
off a toothed rack on the table.
I've had a few questions about the practicalities of using it, so this is some of
what I've learnt.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3766"><img src="https://img.incoherency.co.uk/3766/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3743"><img src="https://img.incoherency.co.uk/3743/thumb"></a></p>
<p>The short answer is that it works a lot better than I expected, and there is a fun trick to creating toolpaths
with normal 3-axis CAM software. If you are tempted to build one of these, you should do it. The only
expensive part is the chuck. You can either borrow the chuck from a nearby mini lathe, or failing that you can
screw workpieces directly onto the plywood gear, or 3d print some sort of fixture. You'll want to keep
the cutting forces low anyway, so the workholding doesn't need to be anything clever.</p>
<p><h2>Principles</h2></p>
<p>There are a few key things you need to know in order to do the calculations to control the rotary axis. The first one is the <b>pitch circle</b> of the 
gear. For metric gears, the diameter of the pitch circle is defined to be the tooth module multiplied by the number of teeth.
The circumference of the pitch circle is the diameter multipled by pi. If you move the Y axis through a distance equal
to the circumference <b>C</b> of the pitch circle then your gear will perform 1 complete revolution.</p>
<p><blockquote><b>Distance for 1 revolution, C = &pi; * module * no. of teeth</b></blockquote></p>
<p>In my case, the tooth module is 3 mm and there are 30 teeth, so for me <b>C = &pi;*3*30 = ~282.74 mm</b>.</p>
<p>If you want to move through an angle of <b>&alpha;&deg;</b>, then you can scale the circumference accordingly.
For example, to move through 90&deg;, you need to move through a quarter of a revolution, because 90 is a quarter
of 360.</p>
<p><blockquote><b>Distance for rotation of &alpha;&deg; = C * &alpha; / 360</b></blockquote></p>
<p>Sometimes it's more useful to work with distances than angles.
For example, if your part has a circumference of <b>C<sub>part</sub></b>
and you want to cut a line of 5 mm on it, how far do you need to move the Y axis? Just multiply 5 by the ratio of
the rotary axis's pitch circle circumference to the part's circumference:</p>
<p><blockquote><b>Distance on the Y axis = distance on the part * C / C<sub>part</sub></b></blockquote></p>
<p>Let's define the ratio <b>R = C / C<sub>part</sub></b>. So if our part is 20 mm in diameter, then it has a circumference of <b>20&pi; = ~62.83 mm</b>, so <b>R = 282.74 / 62.83 = ~4.50</b>.</p>
<p>So to cut a 5 mm line around its circumference we need to move the Y axis by <b>5*R = 5*4.50 = ~22.5 mm</b>.</p>
<p>Feed rates need to be scaled by the same ratio as distances, because we care about the feed rate at the surface of the work piece,
not at the surface of the table. If we want to feed the tool into our 20 mm part at 1000 mm/min, then we need to command the machine
to move the Y axis at <b>1000*R = 1000*4.50 = 4500 mm/min</b>.</p>
<p>Calculating the feed rate gets more complicated for diagonal moves, because distances and feed rates in the X axis
are unaffected by the rotation. You can calculate feed rates for diagonal moves by working out the ratio of the
length of the movement on the table to the length of the actual cut on the work piece (using Pythagoras to work
out the distances - form a triangle with X distance on one side and Y distance on the other, and the hypotenuse is the
total distance of the movement). Multiply your desired feed rate by this ratio. (But if you find yourself having to do
this calculation more than once then you should probably try to find a better way to make your toolpaths).</p>
<p><h2>3-axis CAM</h2></p>
<p>There is a fun trick for making toolpaths for the rotary axis:</p>
<p><ol>
<li>model the part as a flat "unwrapped" equivalent</li>
<li>generate the toolpaths to cut out the flat version</li>
<li>reconfigure Grbl's Y axis using the <b>R</b> ratio calculated above</li>
<li>the toolpath is magically wrapped up onto your cylindrical part</li>
</ol></p>
<p>I modelled this ring in FreeCAD as a flat part:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3790"><img src="https://img.incoherency.co.uk/3790/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3759"><img src="https://img.incoherency.co.uk/3759/thumb"></a></p>
<p>I want the outer diameter of the ring to be 26 mm, so the outer circumference is <b>&pi; * 26 = ~81.68 mm</b>. I modelled
the ring as a flat part that is 81.68 mm long in the Y axis, and generated suitable toolpaths to cut the ring out of a flat piece on the table.</p>
<p>For <b>C<sub>part</sub></b> = 81.68 mm, on my machine, <b>R = 282.74 / 81.68 = ~3.46</b>. Then we just need to update the
Y axis settings as follows:</p>
<p><table border>
<tr><th>Setting</th><th>Linear</th><th>Rotary</th></tr>
<tr><td>$3 (axis invert)</td><td>7</td><td>5</td></tr>
<tr><td>$101 (Y steps/mm)</td><td>320</td><td>320 * 3.46 = 1107.2</td></tr>
<tr><td>$111 (Y max. velocity, mm/min)</td><td>4000</td><td>4000 / 3.46 = ~1150</td></tr>
<tr><td>$121 (Y max. acceleration, mm/sec<sup>2</sup>)</td><td>50</td><td>50 / 3.46 = ~13</td></tr>
</table></p>
<p>The most important setting is $101. This should be set precisely otherwise your toolpaths won't line up properly
with rotations of the chuck. $111 and $121 only need to be set approximately. These are limits to how fast the
machine can move around, so they need to be <i>divided</i> by <b>R</b> to cancel out the multiplication in $101, otherwise Grbl will try to move the machine too fast,
because what Grbl thinks is 100 mm (i.e. what is 100 mm on the work piece) is actualy 346 mm in physical space.</p>
<p>And don't forget to toggle the Y bit in $3, because in rotary mode the top of the part is effectively moving in the opposite direction relative
to the tool.</p>
<p>Also don't forget to put these numbers back when you're done otherwise all your non-rotary parts will be mirrored and stretched in the Y axis!</p>
<p>There are a few really good reasons to do the rotary axis CAM this way:</p>
<p><ul>
<li>a lot more tooling is available for flat 3-axis CAM than rotary CAM.</li>
<li>it will never try to do more than 1 complete rotation, so you'll never drive past the end of the toothed rack, which
is a limitation that most rotary CAM isn't likely to be aware of.</li>
<li>feed rates are scaled automatically, so you don't need to worry about setting your feed rates correctly for X vs Y movements, and in particular you don't need to do any calculations for diagonal moves, and you even get correct arc movements for free.</li>
</ul></p>
<p><h2>"Tailstock" support</h2></p>
<p>I 3d-printed a wheel to support the loose end of a long aluminium cylinder. It is all held tight
by a threaded bar that runs through the middle of the work piece, chuck, and bearings, secured with a nut at
both ends.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3764"><img src="https://img.incoherency.co.uk/3764/thumb"></a></p>
<p>This is <i>OK</i> but not amazing. It stops the part from being ripped out of the chuck in plunge cuts, so it does its job
in that sense. But it does nothing at all in the horizontal plane, so you still get more flex at the end furthest
from the chuck. Also, the wheel is slightly larger than the pitch circle of the rotary axis, which means it wants to roll further
for the same angle of rotation. This means the wheel is constantly slipping against the table.</p>
<p>To stop the wheel from slipping we could make the wheel the same size as the pitch circle of the gear, and put a raised "road"
on the table for the wheel to roll on. A further improvement would be to replace the wheel and road with another gear and rack,
and this would get us some lateral stability as well. If I do much more work with long parts I will probably give this a go.</p>
<p><h2>Rings</h2></p>
<p>I made the wooden ring for myself, and put my initials on it. This was made by hot-gluing a "blank" (cut out
with the CNC machine in its normal linear configuration) to a 3d-printed mandrel held in the chuck:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3753"><img src="https://img.incoherency.co.uk/3753/thumb"></a></p>
<p>The letters and hexagons are cut first, then painted gold, and then the surface is machined down to expose the wood underneath,
leaving the gold paint only in the valleys. Here's a video showing the engraving (sorry about the audio, I don't know what
happened):</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/CVI3hk80DJI" frameborder="0" allow="allowfullscreen" allowfullscreen></iframe></p>
<p>I made this ring to wear at a wedding I attended at the weekend. Since getting married and getting used to wearing a
ring every day, I have really got into wearing rings at special occasions.
So far 4 people have told me I should try to sell these rings, and 2 people have told me I shouldn't, so
to test the water I have made an initial batch of 5.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3795"><img src="https://img.incoherency.co.uk/3795/thumb"></a></p>
<p>I made the batch of 5 in largely the same way as the first one, except with a larger mandrel so I can mount 5 blanks at a time, and I didn't
engrave my initials on them because most people have different initials. They're available <a href="https://www.etsy.com/shop/incoherency">in my etsy shop</a>.</p>
<p>If I were to make more rings I would do them differently. I think these are weaker than they need to be because the grain runs
across the ring in the long direction instead of the short direction. They should have the grain running along the direction
of the finger, rather than perpendicular to the finger. Also, instead of making each of the ring blanks individually and then
measuring their coordinate offsets and machining patterns on them individually, I would start with a single long tube of wood,
with the grain running axially. I'd machine the pattern over the entire surface of the tube without regard for where each ring
is going to start and finish, and then I'd part off individual
rings from this large tube. I think this would be a lot less work.</p>
<p><h2>Cylinder Puzzles</h2></p>
<p>I've designed a puzzle that involves shuffling rods back and forth through a cylinder, to allow the inner "puck" to be removed.
It's a type of maze puzzle where you can see all the parts of the maze, but it's still difficult to find the solution
because the possible movements are so hard to see.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3782"><img src="https://img.incoherency.co.uk/3782/thumb"></a></p>
<p>The one on the left is 3d printed and the one on the right is machined out of aluminium. The machining is not great, and the
part is worse at the end that was further from the chuck, because my "tailstock" support wheel doesn't provide a lot of support,
but it's a very promising start. I still need to make metal versions of the puck and the sliding rods.</p>
<p>For this part I did not use the 3-axis CAM trick. I'm using a similar ASCII-maze-based workflow for this puzzle as I am
for <a href="https://incoherency.co.uk/blog/stories/partypuzzling.html">Party Puzzling</a>, so I wrote a Perl script to turn the ASCII art maze into
G-code.</p>
<p>I started by testing out the machine and the toolpaths on a random piece of plastic pipe:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/q-I_lZVSSlY" frameborder="0" allow="allowfullscreen" allowfullscreen></iframe></p>
<p>It worked, but the (PVC?) plastic pipe does not machine very well at all! It makes a real mess.
I eventually worked up the courage to try it on aluminium:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/vwGdSfLLLjo" frameborder="0" allow="allowfullscreen" allowfullscreen></iframe></p>
<p>I broke the endmill on the first attempt because I was trying to use feeds and speeds borrowed from the web. It seems that
for cutting aluminium with a router you need to use much higher RPM than real machinists would use. I don't know why. From
first principles I think there should be an optimal relationship between RPM and feed rate, so that you're taking a proper
chip and not rubbing the tool
against the work, but it seems that on a router it cuts a lot better (and doesn't break the tool!) if you take much smaller
nibbles than what machinists will tell you to use.</p>
<p>I don't know, maybe I just don't understand.</p>
<p>I found that running the spindle at 8000 rpm and feeding at 800 mm/min worked best. It's a 6mm 2-flute carbide end mill.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/using-the-rotary-axis.html</link>
   <guid>http://incoherency.co.uk/blog/stories/using-the-rotary-axis.html</guid>
   <pubDate>Thu, 24 Mar 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Librem 5: first impressions</title>
   <description><![CDATA[In February 2018 I placed an order for a Librem 5.
Today it finally arrived.]]></description>
   <content:encoded><![CDATA[<p>In February 2018 I placed an order for a <a href="https://puri.sm/products/librem-5/">Librem 5</a>.
Today it finally arrived.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3767"><img src="https://img.incoherency.co.uk/3767/thumb"></a></p>
<p>The Librem 5 does not run Android or iOS, it runs a proper Linux operating system (<a href="https://pureos.net/">PureOS</a>, derived
from Debian). There are hardware kill switches for the baseband modem, the camera and microphone, and WiFi and bluetooth.
The phone's main selling point is that it doesn't spy on you.</p>
<p>If you don't care that your phone is spying on you, then the Librem 5 is not for you. If your response to
complaints like "the camera app is hard to use and can't take video" is "why don't you just buy an iPhone?"
then you have totally missed the point. The Librem 5 is not in the same category of things as the iPhone. Anybody
who would enjoy a Librem 5 would not be able to tolerate an iPhone (and vice versa).</p>
<p><h2>The short version</h2></p>
<p>(For context, my previous phone was a OnePlus One running Ubuntu Touch.)</p>
<p>The Librem 5 is a <i>lot</i> better than I had been led to believe. It's much faster and more responsive than the OnePlus One, and
although I had heard a rumour that phone calls don't work, they work perfectly.
Great success, good job Purism. If you are the kind of person who dismisses Android and iOS
out of hand because you like freedom, then the Librem 5 is a good phone for you and you should buy it (but, again:
if you don't care that your phone is spying on you, then the Librem 5 is not for you).</p>
<p>Notable parts that <b>work</b>:
<ul>
<li><b>WiFi</b> works, no setup required beyond selecting a network and entering the password.</li>
<li><b>Calling</b> works, no setup required beyond installing a SIM card and rebooting.</li>
<li><b>SMS</b> works, no setup required beyond installing a SIM card and rebooting.</li>
<li><b>4G</b> works after you manually setup the <a href="https://www.giffgaff.com/help/articles/internet-apn-settings-guide">APN settings</a>; the phone defaults to Tesco Mobile settings, for some reason.</li>
<li><b>Hosting WiFi hotspots</b> works, no setup required beyond enabling the option.</li>
<li><b>Email</b> works, just the normal IMAP and SMTP setup.</li>
</ul></p>
<p>Notable parts that <b>don't work</b> as well as they should:
<ul>
<li><b>The camera app</b> <i>works</i>, but you have to manually set gain, exposure, white balance, and focus. It also seems to take about 10 seconds to save a JPEG to the disk, so you won't be taking photos very rapidly, and it has no way to record a video, and the quality is bad if there isn't enough light. I find the camera too annoying to use, it is the phone's largest drawback.</li>
<li><b>The default browser</b> has a few input bugs: if the text in a search box is longer than the box, and you want to edit some text that has scrolled out of view, you just can't. There is no way to horizontally scroll the text box in the browser. This is not a general UI bug, it works fine in other apps. There is also no way to open a link in a new tab: long press on a link pops up a context menu, but you can't select anything in the context menu because it disappears as soon as you take your finger off the screen. Firefox is also available (<tt>sudo apt install firefox-esr</tt>) and doesn't have either of these problems.</li>
<li><b>The maps app</b> has a way for you to search for start and end destinations. The search is really bad, it doesn't recognise postcodes and it thinks all towns are in America. Once you have managed to correctly select a start point and an end point, and you want to start navigation, you can't, because the UI disappears off the right hand edge of the screen so you can't reach the "start navigation" button that presumably exists. If you rotate the screen into landscape mode then it now disappears off the bottom edge of the screen and you still can't reach any buttons.</li>
<li><b>The battery life</b> seems short. I'm <i>pretty sure</i> that I charged it up to 99% when I plugged it in this afternoon. It's
now 10pm and I just went to check something in Firefox and found that the battery has died already. And I haven't exactly been using it
heavily. It's possible that I misunderstood how much I had charged it, but so far this is a bad sign.</li>
</ul></p>
<p>The rest of this post is roughly a stream of consciousness of my thoughts as I first interacted with the phone.</p>
<p><h2>Unboxing</h2></p>
<p>It's big. It's heavy. The outer casing is aluminium, I expected plastic.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3768"><img src="https://img.incoherency.co.uk/3768/thumb"></a></p>
<p>It takes USB-C, which is annoying, as I like to live in the past. The charging cable has USB-C on both ends which
means it's not possible to charge from my normal USB charging dock, so I have to use the bundled UK-to-USA-to-USB
power adapter. The UK-USA plug adapter feels sturdier than some that I've used, but not as sturdy as a real 3-pin plug.
The USB-C cable is very chunky, I'm not sure if this is a good sign as it carries lots of power, or is just to fit
with the aesthetic of the rest of the phone.</p>
<p>It asked me for a disk encryption passphrase. At first it wasn't clear whether it was asking me to <i>set</i> a
passphrase, but no. The default passphrase is "123456", once you type that in it boots up.</p>
<p>It seems fast. It booted faster than I expected. I can't drag down from the top bar to access the WiFi setup. How do
I WiFi? Oh, you have to single tap on the top bar, not drag. I need to get used to that. On Ubuntu Touch
you have to drag everything.</p>
<p><h2>Backups</h2></p>
<p>Before I got very far a box popped up asking me to configure backups. It's not clear on whether they
are local or remote, and who would be hosting them if remote.
Normally I would ignore this popup, especially on a phone, but today I'll play along.</p>
<p>Once you've agreed to backup your data, you now get to decide where you want to store it:
Google Drive, "network server", or "local folder". What are the chances it supports sshfs?</p>
<p>I tried an "ssh://" protocol as the "network server", and it says "Unable to find supported SSH command".
So... it kind of supports sshfs? Except not? It knows what it is.</p>
<p><h2>Input & Launcher</h2></p>
<p>I could do with more oomph on the vibrate when you press the keyboard. It feels a bit vague. It's more
noticeable when you're holding it in your hands than when it is sitting on the table.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3769"><img src="https://img.incoherency.co.uk/3769/thumb"></a></p>
<p>The space bar is very close to the little arrow at the bottom of the screen that loads up the app launcher.
So if you are not careful then it pops up the app menu while you're typing.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3770"><img src="https://img.incoherency.co.uk/3770/thumb"></a></p>
<p>The app launcher only uses a third of the screen if there are any apps open, this is annoying. The top third of the screen
is wasted on some sort of alt-tab-style view, with no way to get rid of it other than closing all the
windows. The bottom third is wasted on a keyboard for typing into the search box, so you're left with only 2 rows of
icons visible.</p>
<p>"Parental Controls" doesn't work. It shows a splash screen, spins for a couple of seconds, and then closes.</p>
<p>The Settings tool has an obvious option for whether I want my primary mouse click to be the left button
or the right button, but no apparent option at all for how much haptic feedback I want from the keyboard.</p>
<p><h2>Backups, again</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/3771"><img src="https://img.incoherency.co.uk/3771/thumb"></a></p>
<p>Oh, there is a helpful help icon in the "network server" box on the backups thing that tells you what the
URI should look like. It is a question mark inside a rectangle, so for me it pattern-matched "this unicode
character does not exist in this font" rather than "click here for help". There is nothing to indicate
that it is clickable despite the rest of the UI being the 3d style where it's obvious what is clickable
and what is not. </p>
<p>The help text confirms that I typed my "ssh://" URI correctly, I wonder why it didn't work.</p>
<p>Aha, SSH isn't installed. In a terminal I get <tt>bash: ssh: command not found</tt>. That'll do it.
I installed SSH.</p>
<p>Wow, it's working! It asked me for my SSH password, now it's having me setup some sort of password
keyring. On the first try it tried to write to <tt>/pureos</tt> on the remote server, but after I changed
it to <tt>/home/jes/pureos</tt> it actually worked. It backed up the phone to a network server without any
rando Silicon Valley megacorp getting their grubby mits all over the data. Kudos,
I did not expect that.</p>
<p><h2>Telegram</h2></p>
<p>There is no Telegram app in the PureOS store, however there are a few in apt. I wonder if they will actually
work on the phone screen or if they're just normal desktop programs. I installed <tt>telegram-desktop</tt>
with apt and it automatically shows up in the app launcher, which is a good sign, although it doesn't work.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3779"><img src="https://img.incoherency.co.uk/3779/thumb"></a><br>
<small>Telegrar: Welcome to the officia. It's fast.</small></p>
<p>I mean, maybe it works, but all the input elements are off the screen and I have no way to scroll. I'll use
the browser instead. Web Telegram worked on the first try, and there is even an option in the browser
to install the site
as an application, which adds it as an entry in the app launcher.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3772"><img src="https://img.incoherency.co.uk/3772/thumb"></a></p>
<p>When I open it from the launcher it has
forgotten my cookies so I have to reauthenticate, but after I've done this I can quit it and reopen from
the launcher and it remembers me now. So this is satisfactory.</p>
<p><h2>Terminal</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/3773"><img src="https://img.incoherency.co.uk/3773/thumb"></a></p>
<p>There's no obvious way to type a tab character in the terminal. However there <i>is</i> a way to type
a square root symbol, a pi character, and a tau character. Very useful in my terminal sessions.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3774"><img src="https://img.incoherency.co.uk/3774/thumb"></a></p>
<p>Aha, found it. If you click <tt>&gt;_</tt> next to the space bar it takes you to a page of characters
like Tab,Ctrl,Esc, etc.</p>
<p><h2>Email</h2></p>
<p>Email was completely uneventful. I loaded up Geary, typed in my account details, and it worked straight away.
Great success, no complaints. And "remote images not shown" is default behaviour, as it should be.</p>
<p><h2>Updates</h2></p>
<p>Yay, now it has notified me that I have OS updates to install, one of my favourite tasks.</p>
<p>It's getting a bit warm. However, so is my other phone and I haven't even been using that one, very suspicious.
I only used it to take the photo of the Telegram app. Maybe mere proximity to a Librem is enough to
trigger remote surveillance in other phones?</p>
<p>It can't seem to work out whether it has downloaded the updates or not. There is a button that said "Download"
at first, and then I click it, and it changes to something like "Update & Restart", but before I have a chance
to click it it turns back into "Download".</p>
<p>Sod it, I'll use the terminal. I <tt>sudo apt upgrade</tt> and then reboot the phone. It takes about 9 seconds
from unlocking the disk to fully booting the phone, very impressive. Admittedly it takes about 10 seconds to
unlock the disk, not sure what that is all about.</p>
<p><h2>Camera</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/3775"><img src="https://img.incoherency.co.uk/3775/thumb"></a></p>
<p>The camera is very dark. At first I thought it had some debugging prints overlaid on top of the
picture preview, but it turns out this is the camera UI. You click on the number next to "gain", "exposure",
"balance", or "focus" (focus only available on the back camera) and you get a slider to adjust the corresponding camera property.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3781"><img src="https://img.incoherency.co.uk/3781/thumb"></a></p>
<p>I took that with the Librem camera. Better quality than I had been led to believe.</p>
<p>The camera app was slow, it took a very long time to save the picture.</p>
<p>Hmm, I don't think it can record video.</p>
<p>I briefly entertained the idea that manually controlling the focus is good, because I frequently struggle
to get my OnePlus One to focus properly, but no, it's not good, it's just annoying. It's more annoying than
struggling with the autofocus on the OnePlus One.</p>
<p>Later in the evening I was showing off the camera to Emma, but by this time it was a bit darker, and this
was the best I managed to do:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3780"><img src="https://img.incoherency.co.uk/3780/thumb"></a></p>
<p>It's possible that I blundered the settings, but the camera definitely seems to struggle in low light conditions.</p>
<p><h2>Maps</h2></p>
<p>The pinch zoom on the maps app is really laggy. It also doesn't seem to understand postcodes.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3776"><img src="https://img.incoherency.co.uk/3776/thumb"></a></p>
<p>It can do routing
on the map, but the UI disappears off the right hand edge of the screen so there's no way to confirm that you want
to start following the route. If you unlock screen rotation and make it landscape it no longer disappears off the
right edge, but now it disappears off the bottom edge. Has anybody tried to use this?</p>
<p><h2>Mobile network</h2></p>
<p>I put a SIM card in the phone and opened up the phone app. It says "Can't place calls: No modem or VoIP account available".
At first I thought this was just the natural order of things, because I thought calls didn't work, but Emma suggested
rebooting it to see if that fixed it. I played along, but I knew it wouldn't help.</p>
<p>OK, I rebooted it and now it is showing a 4G symbol in the top bar. Could it be...? Wow, calls work! In
both directions. Worked on the first try, incredible technology. Just make sure you reboot so that it knows you've
installed a SIM card.</p>
<p>It makes a sound effect when an SMS is received, this is bad. I can't find an option to turn off notification sounds
short of turning the volume down to 0. It sounds like if I ever listen to anything, I need to remember to
turn the volume down to 0 afterwards otherwise my phone might be able to make noises. I don't like
it when things make noises.</p>
<p>There doesn't seem to be a way to bulk-import contacts. Maybe this is a terminal window jobby.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3778"><img src="https://img.incoherency.co.uk/3778/thumb"></a></p>
<p>4G worked after I typed in the APN settings for giffgaff. Hosting a WiFi hotspot works. It seems to take a long time
to successfully switch from 4G to WiFi, I don't know why. Once it is connected it works fine, just seems to
take a couple of minutes to connect to WiFi once you've switched 4G off.</p>
<p><h2>Browser</h2></p>
<p>The browser has no "stop" button.</p>
<p>YouTube is popping up its first-run "you need to agree to our terms" modal, but all the text and buttons
are invisible. I tapped around a bit and it's worked now. I'm in YouTube. Video playback on YouTube works
first try, great success.</p>
<p>Ah, but fullscreen doesn't do anything. It just stays non-fullscreen.</p>
<p>I wonder if Slack works. I'm guessing not because Slack won't let you use it if you don't have an authorised
User-Agent string. Indeed, it doesn't work.</p>
<p>I can't open links in a new tab. Long press pops up a menu that includes the option, but in order to select the
option I need to let go of the screen, and when I let go the menu disappears. Holding my finger on the screen
and dragging it to the option also doesn't work.</p>
<p><h2>Firefox</h2></p>
<p><a href="https://www.grahamedgecombe.com/">Graham</a> told me I can get Firefox with the <tt>firefox-esr</tt> package.
I did, and Slack works in Firefox, albeit very slowly.</p>
<p>Opening links in a new tab works in Firefox. Fullscreen video works in Firefox.</p>
<p><a href="https://dartoxia.com/">Ben</a> remarked that it is weird that the default browser isn't just Firefox.</p>
<p><h2>Conclusion</h2></p>
<p>I'm glad the phone has finally arrived.
I think it's a lot better than most people are saying. From reading the
<a href="https://old.reddit.com/r/Purism/">r/Purism</a> subreddit you'd get the impression that the phone doesn't
work and everyone is asking for a refund. It's certainly better than my OnePlus One, with the exception of the
camera, and possibly the battery life.</p>
<p>I very rarely take my OnePlus One anywhere with me unless I know I'm likely to need it, because I reject on principle the
notion of carrying an always-on tracking beacon that logs my movements in the phone companies' databases.
With a hardware kill switch for the baseband modem, I can now carry the Librem 5 around without having to care
about that, and I'm able to turn it on as and when I want to make a call or use 4G.</p>
<p>Maybe I'll try to fix some of the little annoyances with the phone (the "please take me to the launcher" arrow
being mere pixels away from the "please input a space" button seems likely to be an easy fix). And hopefully the
battery life isn't too awful.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/librem5-first-impressions.html</link>
   <guid>http://incoherency.co.uk/blog/stories/librem5-first-impressions.html</guid>
   <pubDate>Mon, 21 Mar 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Packing puzzle: Six Fit</title>
   <description><![CDATA[I've designed a new 2d packing puzzle. It's called "Six Fit" and you have to fit 6 pentominoes into a rectangular tray.]]></description>
   <content:encoded><![CDATA[<p>I've designed a new 2d packing puzzle. It's called "Six Fit" and you have to fit 6 pentominoes into a rectangular tray.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3760"><img src="https://img.incoherency.co.uk/3760/thumb"></a></p>
<p>If you want to 3d print it, you can <a href="https://www.prusaprinters.org/prints/151581-six-fit-2d-packing-puzzle" class="btn btn-primary">download it from prusaprinters</a>.</p>
<p>I don't know if you're familiar with <a href="https://en.wikipedia.org/wiki/Stewart_Coffin">Stewart Coffin</a>'s puzzle "Four Fit" (aka "Martin's Menace" because <a href="https://en.wikipedia.org/wiki/Martin_Gardner">Martin Gardner</a> said "It looks easy but is fiendishly difficult. I wasted a week trying vainly to solve it"). There is a 3d-printable version of Four Fit <a href="https://www.thingiverse.com/thing:3403252">on thingiverse</a>.</p>
<p>Four Fit is so difficult because the solution involves placing the pieces so that they are not aligned with the apparent axes of the box you need to put them in.</p>
<p>There is also a "Five Fit" puzzle, available for example <a href="https://cruxpuzzles.co.uk/product/five-fit-puzzle/">here</a>.</p>
<p>However I have not yet been able to find an example of a <i>Six Fit</i> puzzle, so I wrote <a href="https://github.com/jes/packominoes">some code</a> to find one for myself, and I found this one.</p>
<p><h2>Searching for puzzles</h2></p>
<p>My "packominoes" tool generates grids skewed away from the axes. It searches for possible skewings where a section of the skewed grid
intersected with an axis-aligned bounding box leaves a given number of squares available. Having found a suitable skewed grid, another
program brute forces the set of all sets of pentominoes to try to find a set of pieces which can pack into the skewed grid, but which
<i>cannot</i> pack into the largest axis-aligned grid that fits within the axis-aligned bounding box.</p>
<p>A generated puzzle, then, is an axis-aligned bounding box and a set of pieces.</p>
<p>Here's a diagram showing how the skewed grid and the bounding box interact for Six Fit:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3761"><img src="https://img.incoherency.co.uk/3761/thumb"></a></p>
<p>There's a bit more info in my <a href="https://github.com/jes/packominoes">packominoes</a> github repository.</p>
<p><h2>More puzzles</h2></p>
<p>I expect it would also be possible to find a Seven Fit and possibly Eight Fit, although the chances get slimmer as the numbers get higher because the number of possible ways to fit the pieces together start making it impossible to find a box that permits a "diagonal" solution without also permitting an "orthogonal" solution. Hope that makes sense.</p>
<p>We could also search for new variations for low-numbered packing puzzles of this type, using different sets of pieces. 
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/six-fit-puzzle.html</link>
   <guid>http://incoherency.co.uk/blog/stories/six-fit-puzzle.html</guid>
   <pubDate>Thu, 17 Mar 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>A weird rotary axis for my CNC machine</title>
   <description><![CDATA[I've built a weird rotary axis for my CNC machine. Rather than a "4th axis" driven by its own motor,
this one is geared off the motion of the gantry. It's still only a 3-axis machine, and there are no electronics changes at all.
As the gantry drives back and forth, a toothed rack on the table causes a matching gear to rotate. The gear holds a chuck,
which holds the work piece, so that when the gantry moves the work piece rotates.]]></description>
   <content:encoded><![CDATA[<p>I've built a weird rotary axis for my CNC machine. Rather than a "4th axis" driven by its own motor,
this one is geared off the motion of the gantry. It's still only a 3-axis machine, and there are no electronics changes at all.
As the gantry drives back and forth, a toothed rack on the table causes a matching gear to rotate. The gear holds a chuck,
which holds the work piece, so that when the gantry moves the work piece rotates.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3743"><img src="https://img.incoherency.co.uk/3743/thumb"></a></p>
<p>And here's a video of surfacing the face of the gear so that the chuck can be mounted square:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/UEkZtMw4vts" frameborder="0" allow="allowfullscreen" allowfullscreen></iframe></p>
<p>I made this rotary axis because I have a new puzzle design which I want to make out of metal, and it requires machining all the way around
a cylinder.</p>
<p><h2>Why not a traditional 4th axis?</h2></p>
<p>A 4th axis is normally mounted on the table, and controlled by its own stepper motor, indepdendently of the other 3 axes:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3746"><img src="https://img.incoherency.co.uk/3746/thumb"></a></p>
<p>I initially wanted to build a real 4th axis, but decided it was too much trouble, because Grbl only supports 3 stepper motors.
There are Grbl derivatives which can do more, but they require more capable hardware than an Arduino Uno, and I can't be bothered rejigging all
of the electronics. So my next thought was to use the Y-axis stepper driver to control a rotary axis. When I wanted to use the rotary axis
I would unplug the Y motor and plug its cable into my 4th motor. The downside is that I would still need to acquire a 4th
motor.</p>
<p>Then one morning, while lying in bed, I was pondering some more on how to do this. I had some ideas about disconnecting the gantry from the leadscrew, and
adding a bunch of bevel gears, with a shaft driven off the leadscrew, running vertically up through the table, but then it occurred to me that I could leave the gantry
connected to the leadscrew and control the rotary axis with the gantry's movement relative to the table! This seemed like much too weird
an idea to pass up, so I was compelled to implement it.</p>
<p>I wrote a few paragraphs about the idea to some friends, and in a <a href="https://old.reddit.com/r/hobbycnc/comments/t5mary/weird_idea_for_a_4th_axis/">post on reddit</a>, but mostly people either didn't understand or didn't think it was a good idea. One person
linked me to a Perry Projects <a href="http://perryprojects.blogspot.com/2017/08/cnc-4th-axis.html">blog post from 2017 with the same idea</a>, which was
quite encouraging.</p>
<p><h2>Design</h2></p>
<p>I took some measurements from the machine, modelled the important pieces in CAD, and then designed the rack, gear, and mounting
plates to match:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3729"><img src="https://img.incoherency.co.uk/3729/thumb"></a></p>
<p>The 3 bolt holes in the mounting plates are deliberately oversized, to provide wiggle room for alignment. I need to be able to slide the plates
up and down to ensure a tight engagement of the gear teeth (I don't want any free play at all), and I need to be able to slide them
forwards and backwards to ensure that the spindle is centered on the centre of the cutting tool.</p>
<p>The gear has a step in it to fit the recess in the back of the 80mm 3-jaw chuck from my mini lathe.</p>
<p>The shaft is made out of what's left of a pneumatic cylinder I made a few years ago, it was chosen because I have already
cut a thread on one end, and it was almost the right diameter to suit 2 large bearings that I already had.</p>
<p>Finally (not pictured) there is a 3d-printed spacer behind the gear to provide clearance for the nuts holding the chuck, and a 3d-printed "bung"
to screw up the end of the shaft to prevent it from falling out. Ideally there would be a spacer between the 2 bearings but I had already
pressed them in by the time I thought of this. If this proves problematic I can always knock one of them back out and fit a spacer in future.</p>
<p><h2>Build</h2></p>
<p>Making the plywood parts is easy, it's just normal CNC work. They're made out of offcuts of Russian Birch plywood that I bought
for <a href="https://incoherency.co.uk/blog/stories/scamp-case.html">my SCAMP case</a>. I really like this material, it leaves a nice crisp cut with very little
tearing. There are only 5 parts: the gear, the rack, and 3 identical plywood plates, with a bearing pressed into each of the outer plates.</p>
<p>The gear needed 2 setups (top side and bottom side), because there is a step in the front to fit the chuck, and there are also recesses in the back for the nuts
to sit in. In hindsight I could have done it in a single setup: I could skip the step in the front because I needed to re-cut this later anyway.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3732"><img src="https://img.incoherency.co.uk/3732/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3731"><img src="https://img.incoherency.co.uk/3731/thumb"></a></p>
<p>I don't have any pictures from making the shaft. It is a steel tube with a female thread on one end, turned down on the lathe
to 25mm and lightly polished. It's
worth taking your time getting this right as you don't want any play between the shaft and the bearings.
I have a very agricultural "moving steady-rest" that fits this tube
(which you can <a href="https://www.youtube.com/watch?v=tO_Axm2wm8U">see in action here</a>), but I still got quite a lot of
chatter, so polishing the surface was really necessary.</p>
<p>Most of the squareness requirements are provided "for free" because the plywood surface is already flat (enough), and the gantry is already
parallel (enough) to the Y and Z axes of the machine. The only tricky part is making sure the shaft is properly perpendicular to the gear. If it's not,
then the gear will wobble as the shaft rotates and so will the work piece.</p>
<p>I didn't have a good plan for fixing the gear to the shaft. I just dripped a load of superglue in the hole and then pressed the shaft in
with the vice. It is a good tight fit and seems secure, but unfortunately it was about 1&deg; out of square, which was very disappointing,
and I didn't immediately know what to do about it.</p>
<p>As I left the 3 plywood plates gluing up overnight, I realised that I could use the CNC machine to square up the face of the gear for me!
I just need to drive the gantry back and forth with the cutting tool up against the gear, and it
will automatically cut it square. What a relief! In some sense it was a blessing that I failed to glue the gear square to the shaft,
because it forced me to come up with this alternative and superior method.</p>
<p>Next we need to bolt the mounting plates to the gantry. I cut out a cardboard template and aligned it with
the approximate required position of the mounting plates, marked the holes on the gantry, and drilled them:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3734"><img src="https://img.incoherency.co.uk/3734/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3736"><img src="https://img.incoherency.co.uk/3736/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3737"><img src="https://img.incoherency.co.uk/3737/thumb"></a></p>
<p>I drilled the gantry holes 8.5mm to accept M8 bolts, with the idea that I could drill this out to 10mm or 12mm if I need more wiggle
room for alignment, but in the end I didn't need it, the oversized holes in the mounting plates were enough.</p>
<p>The rack is just screwed straight down to the table:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3739"><img src="https://img.incoherency.co.uk/3739/thumb"></a></p>
<p>I was able to fit everything together so that the gear is nice and tight in the rack, and there is no discernible play in any direction,
which I'm very happy with.</p>
<p>An unexpected benefit of making the shaft out of a hollow tube is that you can sight down the bore to check how it is centered on the
cutting tool:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3738"><img src="https://img.incoherency.co.uk/3738/thumb"></a></p>
<p>With the shaft installed, I surfaced the gear (shown in the video at the top) and fitted the chuck:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3743"><img src="https://img.incoherency.co.uk/3743/thumb"></a></p>
<p><h2>Next</h2></p>
<p>Obviously the next step is to use this to make an actual part. I've only just finished building it, and so far the only cuts
I have made were to surface the faceplate.
I now need to write some software to turn my puzzle parts into G-code, and then I can try to make one out of a piece of plastic pipe,
and only when that is successful will I try to make one out of aluminium or brass.</p>
<p>I'm not sure if I'm going to need tailstock support. Perry's Project uses a wheel that rolls along the table to support the far end of the
work piece. Maybe I would do something similar:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3744"><img src="https://img.incoherency.co.uk/3744/thumb"></a></p>
<p><h2>Limitations</h2></p>
<p>On a "normal" 4th axis, you can spin the part around and around forever, but with the one I have built there is
a very limited range of motion, because if you try to move the Y axis too far
you fall off the end of the toothed rack. This also means that we can't easily use traditional 4-axis CAM software, because
it doesn't know that it has to "rewind" periodically to stop itself from running out of bounds. But my CAM software of choice
is FreeCAD, and that doesn't support a 4th axis anyway.</p>
<p>We also can't do things like using this as an indexing head to machine flat features on different sides of a part, because the cutting
tool is always centered on the axis of rotation.</p>
<p><h2>Useful resources</h2></p>
<p>If you want to learn about building rotary axes, you might enjoy watching This Old Tony's <a href="https://www.youtube.com/watch?v=jkgmjIlOVKc">4th Axis Build</a> and <a href="https://www.youtube.com/watch?v=mAZei3wpBe0">CNC Lathe</a> videos.</p>
<p>If you want to cut a toothed rack, then KHK Gears have a very useful page on <a href="https://khkgears.net/new/gear_knowledge/gear_technical_reference/involute_gear_profile.html">the involute gear profile</a>, including a diagram with all the important dimensions explained (apart from <b><i>s</i></b> and <b><i>e</i></b>, which I gather you adjust to get the tooth clearance you desire?):</p>
<p><a class="img" href="https://img.incoherency.co.uk/3745"><img src="https://img.incoherency.co.uk/3745/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/cnc-rotary-axis.html</link>
   <guid>http://incoherency.co.uk/blog/stories/cnc-rotary-axis.html</guid>
   <pubDate>Thu, 10 Mar 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Party Puzzling: themed puzzle sets for special occasions</title>
   <description><![CDATA[Emma and I are now selling themed puzzle sets for use as entertaining party favours
for events like weddings, and stag and hen parties. The idea is that you'd
buy enough to give one to every attendee, and people who want to can try
to solve it, and regardless they can take it home afterwards. There's also a competitive
element: each puzzle has a QR code inside which the successful player can scan to add their 
name, and solve time, to the event's private online leaderboard.]]></description>
   <content:encoded><![CDATA[<p>Emma and I are now selling themed puzzle sets for use as entertaining party favours
for events like weddings, and stag and hen parties. The idea is that you'd
buy enough to give one to every attendee, and people who want to can try
to solve it, and regardless they can take it home afterwards. There's also a competitive
element: each puzzle has a QR code inside which the successful player can scan to add their 
name, and solve time, to the event's private online leaderboard.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3718"><img src="https://img.incoherency.co.uk/3718/thumb"></a></p>
<p>It's called "Party Puzzling" and we have a website at <a href="https://partypuzzling.co.uk/">partypuzzling.co.uk</a> and an
Etsy shop at <a href="https://www.etsy.com/uk/shop/PartyPuzzling">https://www.etsy.com/uk/shop/PartyPuzzling</a>. Right
now we're charging &pound;7.50 per puzzle. They cost about &pound;2 in materials and I can only produce 8 per day, so we're not
going to get rich off this any time soon. But I still think it's a fun idea.</p>
<p>We first did this for our own wedding, with chess-themed puzzles, and people liked it, which is why we're making
them available for sale. We're offering Easy, Medium, and Hard difficulty options, although I still haven't completely finalised
the difficulty calibration. Every puzzle in the same order will get the same maze.</p>
<p>The puzzles consist of a maze on the inside of a cylinder, and a peg on the inner piece
which follows the track of the maze. To get the inner piece out you need to solve the maze, which is
tricky because you can't see it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3719"><img src="https://img.incoherency.co.uk/3719/thumb"></a></p>
<p>So far we only have the beer bottle theme up for sale, but the chess piece theme is mostly finished and
will probably go up on Etsy soon. If you have any good ideas for puzzle themes please let me know!
A good theme would be a well-known object with a roughly cylindrical shape, with a sensible "parting line" to allow the 2 halves
to rotate.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3720"><img src="https://img.incoherency.co.uk/3720/thumb"></a></p>
<p><h2>Maze design</h2></p>
<p>The thing that makes hidden mazes hard for most people is that they don't know the general technique for solving them. Most mazes
can be trivially solved by simply holding your left (or right) hand against the left (or right) wall, and following the left
(or right) wall until you reach the exit. This works even if you have no way to find out whether you've already visited a
given point in the maze. You don't need to remember anything, it just automatically follows the walls all the way to the exit.</p>
<p>If you didn't already know this algorithm, perhaps you want to convince yourself of its correctness. Here's an easy
example you can try it out on:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3713"><img src="https://img.incoherency.co.uk/3713/thumb"></a></p>
<p>You should be able to see that by following one of the walls you expect to explore 50% of the maze before you find the exit.
If you can't see any more than your immediate surroundings (which you can't if the maze is invisible) then no algorithm can
do better than this in the general case (I claim but do not prove).</p>
<p>You might think (as I did, before I thought about it enough) that this only works because there are no cycles in the maze.
You might think that if we add a cycle, then it is possible to get trapped on the cycle:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3714"><img src="https://img.incoherency.co.uk/3714/thumb"></a></p>
<p>Not so. Far from trapping the player on the cycle, you actually <i>isolate</i> the player from the cycle! There is no way
to add a cycle whose walls are connected to the outside walls of the maze (otherwise it's not a cycle), which means there
is no way for a player who is following the walls of the maze to reach the cycle in the first place. (Although it is true that
a player who reaches the cycle by some other method, and then begins to follow the left-hand-wall algorithm, will indeed
remain trapped.)</p>
<p>However, putting the maze on the inside of a <i>cylinder</i> gives us a distinct advantage! Represented on a 2D drawing,
the left-hand edge of the maze wraps around to the right-hand edge. If we make a cycle that wraps all the way around the
circumference of the cylinder, then we <i>can</i> trap the player in the cycle, and isolate them from the rest of the maze:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3715"><img src="https://img.incoherency.co.uk/3715/thumb"></a></p>
<p>So we can use this trick to make the mazes challenging even for people who know the left-hand-wall algorithm :).</p>
<p><h2>Build pipeline</h2></p>
<p>Manually designing cylindrical mazes in FreeCAD is really annoying, so I have quite a fun build pipeline.</p>
<p>I first draw an ASCII art maze in vim, a simple example would look something like:</p>
<p><pre><code>- ----------
|         | 
- --- - --- 
    | | |   
------- --- 
| |     |   
- ----- --- 
        |   
- --- - ----
    | |     
- ----------
            
------------</code></pre></p>
<p>I then have a Perl script which reads in the ASCII art maze and produces an OpenSCAD source file that produces
a 3D model of a <i>flat</i> maze:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3716"><img src="https://img.incoherency.co.uk/3716/thumb"></a></p>
<p>To save time, I also have a Perl script which can generate the ASCII art mazes, and another script that can take in
a maze and give a number for how complicated it is. I run these 2 together in a loop to search for mazes of the
appropriate difficulty. Finding a metric for how difficult it is to solve a maze is quite hard, so there's still a lot
of manual "curation" here. A key part of the measure is the question:</p>
<p><ul>
<li>How many places does the player have to make a turn that is not at the end of a corridor? I.e. how many times do
they have to preemptively attempt to turn a corner without any tactile feedback that a corner exists?</li>
</ul></p>
<p>Having got an ASCII art maze ready, I have <a href="https://github.com/jes/stlwrap">a rust program</a> that reads in an STL file and wraps it up into
a cylinder. This works by splitting large triangles up into tiny ones, and then rewriting the coordinates by interpreting
them as Polar coordinates and rewriting them as the Cartesian equivalents:</p>
<p><ul>
<li>The <b><i>x</i></b> input coordinate gives an angle of rotation around the <b><i>z</i></b> axis</li>
<li>The <b><i>y</i></b> input coordinate gives a radius away from the <b><i>z</i></b> axis</li>
<li>The <b><i>z</i></b> coordinate is unchanged</li>
</ul></p>
<p><a class="img" href="https://img.incoherency.co.uk/3717"><img src="https://img.incoherency.co.uk/3717/thumb"></a></p>
<p>And I can run a command like <tt>mkpuzzle beer easy-maze</tt> which will use the above steps to generate an STL
file from the ASCII art in <tt>easy-maze</tt>, and merge it with the manually-modelled outer part of the
<tt>beer</tt> theme, ready for 3D printing.</p>
<p><h2>Online leaderboards</h2></p>
<p>For our wedding I generated a load of random hex strings to use for the leaderboard codes.
I thought it would be funny if there was an extra layer to this, so instead
of just choosing random hex strings and putting a list of them in a database,
I made the rule that all strings with a SHA256
sum beginning <tt>beef42...</tt> were accepted as valid codes. With the idea that <i>if</i> anyone went to the trouble of finding
out the SHA256 sum of more than 1 code, then they might get some joy out of making a "keygen" and submitting
hundreds of falsified entries to the leaderboard.</p>
<p>Unfortunately, restricting the search so tightly led to me creating a handful of duplicate
codes without realising it, so a couple of the guests found that when they solved the puzzle
and tried to scan the code, it was rejected. Egg and my face were in alignment!</p>
<p>So for Party Puzzling I am just generating a bunch of random strings and putting them in the database.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/partypuzzling.html</link>
   <guid>http://incoherency.co.uk/blog/stories/partypuzzling.html</guid>
   <pubDate>Thu, 24 Feb 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>An Arduino-based USB interface to the Psion Organiser II</title>
   <description><![CDATA[I built a hacky USB interface to the Psion Organiser II that
lets you send messages to it over USB serial via an Arduino Nano. It involves the organiser executing machine code stored in a string
in its BASIC-like language, and it totally abuses the CPU's bus design. But it's simple and it works.]]></description>
   <content:encoded><![CDATA[<p>I built a hacky USB interface to the <a href="https://en.wikipedia.org/wiki/Psion_Organiser">Psion Organiser II</a> that
lets you send messages to it over USB serial via an Arduino Nano. It involves the organiser executing machine code stored in a string
in its BASIC-like language, and it totally abuses the CPU's bus design. But it's simple and it works.</p>
<p>The motivation is that <a href="https://falkus.co/2022/01/2021-retrospective">Martin wanted to use the Psion to display notifications</a>,
but couldn't find anywhere to buy the "CommsLink" module that connects it to a PC. I thought it sounded like a fun Arduino project, so
I did it.</p>
<p>This is what the Psion looks like, with my homemade comms module plugged in:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3696"><img src="https://img.incoherency.co.uk/3696/thumb"></a></p>
<p>My code and 3d printing files are all available <a href="https://github.com/jes/psion-arduino">on github</a>.</p>
<p>If you are working with one of these devices then you should see <a href="https://www.jaapsch.net/psion/">Jaap's Psion II Page</a>. It has
lots of good information and documentation.</p>
<p><h2>Hardware</h2></p>
<p>The Psion actually has 3 slots that peripherals can be plugged into. The first 2 are on the bottom of the device and are used
to insert "datapaks". These are UV-erasable EPROMs which can be used to store code and data. The Psion has a weirdo "write-only"
filesystem built on top of these EPROMs, which (I assume) "deletes" files by writing a bit to say that the file is no longer there, but
can not reclaim used space. The only way to reclaim the space is to expose the little die window to UV light and erase the entire thing:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3682"><img src="https://img.incoherency.co.uk/3682/thumb"></a></p>
<p>The third slot, the "top slot", is the one we're going to be using. It has 16 pins.
The important pins are D0..D7 which are connected directly to the CPU's "port 2" data bus. There's also ground, +5v, and various other
signals which we can ignore. Jaap has a page on <a href="https://www.jaapsch.net/psion/topslot.htm">top slot technical data</a></p>
<p>My first thought for the easiest way to write bytes from the Arduino into a program running on the Psion is to just assert the byte
onto the port 2 bus and leave it there permanently. Then the program on the Psion can sample the bus at its own convenience. When we
have another byte to send, we assert that byte instead, and the Psion will know it's a new byte because the value has changed. If we
need to be able to write duplicate bytes then we can stick a 0x00 in between.</p>
<p>Unfortunately, this isn't quite enough, because it prevents the datapaks from working.
All 3 slots are connected to the same bus of the CPU, but
with 1 pin that tells you whether that slot is selected (CS1, CS2, CS3).
Most of the pins are identical between all 3 slots. If you try to assert something onto the bus while some other peripheral
is trying to use it, then you get <a href="https://en.wikipedia.org/wiki/Bus_contention">bus contention</a>, which means in the best
case the computer doesn't work properly, and in the worst case is permanently damaged.</p>
<p>So what do we do about this? The ideal solution is to put some glue logic between the Arduino and the organiser that tests the CS3 pin
(and "output enable" preferably) and only tries to assert anything to the bus when the top slot is selected, and the CPU is trying to read
from the bus rather than write to it. (It's not sound to do this logic in software on the Arduino because even at 16x the clock speed of the
Psion, the Arduino is not fast enough).</p>
<p>But since we know that the only other devices connected to the bus are the datapaks and the CPU, and we know that those things all respect
the control signals properly, and we only need unidirectional communication, we can take a bit of a shortcut. I connected some digital
outputs of the Arduino to the data pins via 510 ohm resistors (chosen mostly at random). This is low enough resistance to overcome the internal pullups on the data
lines, but high enough that it doesn't interfere when the datapaks or CPU are trying to write to the bus. It's a really simple solution
and seems to work well. So that's the hardware problem solved, the rest is just software.</p>
<p>I initially got this to work on a breadboard, but built it up on a stripboard once I knew it worked:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3684"><img src="https://img.incoherency.co.uk/3684/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3688"><img src="https://img.incoherency.co.uk/3688/thumb"></a></p>
<p>Connecting a 2-row pin header to a stripboard is not easy because there is no sensible way to connect to both rows. I solved this by
soldering the connector on one side and supergluing it on the other:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3687"><img src="https://img.incoherency.co.uk/3687/thumb"></a></p>
<p>(And, actually, I didn't even have a 2-row header on hand, so I made this one by gluing two single-row headers together).</p>
<p><h2>Software</h2></p>
<p>We need to be able to read from port 2 and write to the display.  
The Psion has a programming language called "OPL". It's more or less the same as BASIC. Writing to the display is easy, because we can
just use <tt>PRINT</tt> and have OPL sort it out for us. Reading from port 2 is more tricky.</p>
<p>Jaap's page on <a href="https://www.jaapsch.net/psion/sysvars.htm">The System Variables</a> is very helpful. We learn that port 2
is accessed at memory address 0x0003, and the direction (read or write) of the pins is controlled at address 0x0001:</p>
<p><blockquote>Port 2 data direction register. Bit 0 controls the direction of bit 0 of [port 2] (1=output,0=input) and bit 1 control the direction of bits 1-7 of [port 2].</blockquote></p>
<p>So we need to write zeroes into address 0x0001, and then read bits from the data pins in the top slot by reading
address 0x0003.</p>
<p>It turns out we also need to tell the organiser that we want to use the top slot rather than one of the other slots. I'm not sure if
one of the datapaks is left active if you don't do this, but I couldn't get it to work without asking for the top slot to be active.</p>
<p>We control which slots are active by writing to port 6. See Jaap's page for more info.</p>
<p>OPL has a <tt>POKEB</tt> command which can be used to write bytes into arbitrary addresses, and it has a <tt>PEEKB()</tt> function which
can be used to read from arbitrary addresses. Great success, right? We just poke and peek and we can read from the top slot.</p>
<p>Not so fast! Just to make life more interesting, OPL deliberately blocks any attempt to read or write an address below 0x0040. This is very
frustrating. It's probably done to "prevent you from breaking your device", but a.) if you're writing values into random memory addresses you
should already have some idea of the risk, and b.) you can still break your device anyway with the workaround.</p>
<p>The workaround is to write some assembly language code to do your memory accesses, assemble it by hand, write the bytes into a string,
and then execute the string from OPL as if calling a native machine code routine (which you are). Easy enough, but it's annoying
that it's necessary. It wouldn't have been any trouble for
them just not to block access from OPL! (In fact, come to think of it, maybe the easiest way to circumvent it is actually to work out where in memory
<tt>POKEB</tt> and <tt>PEEKB()</tt> are implemented, and NOP out the test...)</p>
<p>I was very excited when I managed to use some machine code to read data from the top slot, then get those bytes back to OPL,
print them to the screen, and observe that they changed when I pulled one of the pins on the bus high:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/K6THWVoLX60" frameborder="0" allow="allowfullscreen"></iframe></p>
<p>And then even better when I first got the complete pipeline working, getting text typed on Linux displayed on the Psion:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/enHQhHhHgmw" frameborder="0" allow="allowfullscreen"></iframe></p>
<p>I eventually reached the following machine code routine to set port 2 to what I want, read a byte from it, stick the byte in the X register, and
return (in my made-up assembly language dialect):</p>
<p><pre><code>72 18 16  oim $18, $16 # allow writing to bits 0x10,0x08 in port 6
71 18 17  aim $18, $17 # enable the top slot and disable the other 2 slots
71 00 01  aim 0, $01 # input mode on port 2
96 03     ld a, ($03) # read from port 2 into A
c6 00     ld b, 0
36        push a
37        push b
38        pull x # make a 16-bit value out of a 0 and the byte we read
39        rts</code></pre></p>
<p>I wrote this by consulting Jaap's <a href="https://www.jaapsch.net/psion/mcmnemal.htm">HD6303 instruction set documentation</a>.</p>
<p>I have never programmed a HD6303 before, so some of this is probably stupid (like spending 4 instructions to extend a byte in
A to 2 bytes in X), but it does the job. With machine code in hand, we just have to write an OPL program to execute it.</p>
<p>I ended up with this:</p>
<p><pre><code>DISPLAY:
LOCAL S$(17),A%,B%,C%
POKEB $7C,0
S$=CHR$($72)+CHR$($18)+CHR$($16)+CHR$($71)+CHR$($18)+CHR$($17)+CHR$($71)
S$=S$+CHR$(0)+CHR$(1)+CHR$($96)+CHR$(3)+CHR$($C6)+CHR$(0)+CHR$($36)
S$=S$+CHR$($37)+CHR$($38)+CHR$($39)
WHILE KEY<>0:ENDWH
WHILE KEY=0
A%=USR(ADDR(S$)+1,0)
IF A%<>B%
C%=USR(ADDR(S$)+1,0)
IF A%=C%
IF A%<>0
PRINT CHR$(A%);
ENDIF
B%=A%
ENDIF
ENDIF
ENDWH</code></pre></p>
<p>The local variable <tt>S$</tt> holds our machine code. Strings in OPL have 1 byte saying how long they are, followed by
the contents of the string. <tt>ADDR(x)</tt> gives us the address of a variable, and <tt>USR(addr, arg)</tt> executes some machine
code. So we can execute our code by calling <tt>USR(ADDR(S$)+1,0)</tt>. I didn't figure this out on my own, I got it from
Jaap's <a href="https://www.jaapsch.net/psion/mctutor1.htm">machine code tutorial</a>.</p>
<p>The initial <tt>POKEB $7C,0</tt> asks the Psion not to switch off the screen after a period of inactivity. The main loop
is inside <tt>WHILE KEY=0</tt> so that you can exit it by pressing any key.</p>
<p>The main loop reads a byte from the top slot. If the value is different to the last known value, then it reads again. If this second
read is different, then it ignores them both. This is so that we don't get corrupted reads while the Arduino program is
halfway through updating the values on the bus.</p>
<p>Having determined that 2 consecutive reads got the same value, we print the byte to the screen unless it's 0 (which is used to
delimit consecutive outputs), then we update the last known byte to whatever we just read and loop again.</p>
<p>Although the current implementation is only unidirectional, it is probably possible to invent a protocol by which the "writer" can signal
to the "reader" that it wants to swap roles, and then both sides invert their bus direction. I'm not sure if we'll need to do this, but
hopefully it would only require a software change.</p>
<p><h2>3D Printing</h2></p>
<p>The last thing to do is make a nice plastic enclosure for the electronics. I recently fitted a 0.6 mm nozzle to my Prusa Mini (previously
I was using the standard 0.4 mm nozzle). I think
this is a great upgrade. You can print parts a lot faster, they're (supposedly) a bit stronger, and the nozzle doesn't clog as easily
because larger impurities can pass straight through. The
loss of detail is minimal, and only exists in the X/Y plane because you can still print with the same layer heights if you want.
I think 0.6 mm should be the default!</p>
<p>I really like countersunk allen screws, I think they give a nice finish sitting flush with the surface of the part.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3698"><img src="https://img.incoherency.co.uk/3698/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3690"><img src="https://img.incoherency.co.uk/3690/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3691"><img src="https://img.incoherency.co.uk/3691/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3692"><img src="https://img.incoherency.co.uk/3692/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3693"><img src="https://img.incoherency.co.uk/3693/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3694"><img src="https://img.incoherency.co.uk/3694/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3697"><img src="https://img.incoherency.co.uk/3697/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/psion-organiser-ii-arduino-usb-interface.html</link>
   <guid>http://incoherency.co.uk/blog/stories/psion-organiser-ii-arduino-usb-interface.html</guid>
   <pubDate>Sat, 05 Feb 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Waypointer Moto: motorcyle navigation for Bangle.js</title>
   <description><![CDATA[I have made a Bangle.js app for motorcycle navigation. It's called
"Waypointer Moto" which is a bit of a mouthful but it doesn't matter. Instead of telling
you exactly which roads to use to reach your destination, it just points an arrow directly at your destination and
tells you the straight-line distance. It tells you where you're trying to end up, but leaves the route-finding
and exploring of the environment up to the user.
The idea is that you end up riding new roads and discovering places you
would never normally come across. It's a middle ground between riding around at random, and following
a route dictated by a satnav.]]></description>
   <content:encoded><![CDATA[<p>I have made a <a href="https://banglejs.com/">Bangle.js</a> app for motorcycle navigation. It's called
"Waypointer Moto" which is a bit of a mouthful but it doesn't matter. Instead of telling
you exactly which roads to use to reach your destination, it just points an arrow directly at your destination and
tells you the straight-line distance. It tells you where you're trying to end up, but leaves the route-finding
and exploring of the environment up to the user.
The idea is that you end up riding new roads and discovering places you
would never normally come across. It's a middle ground between riding around at random, and following
a route dictated by a satnav.</p>
<p>If you want to try it out, you can get it on <a href="https://jes.github.io/BangleApps/#wpmoto">my fork of the BangleApps loader</a>,
or, eventually, on <a href="https://banglejs.com/apps/#wpmoto">the official BangleApps loader</a>. Read <a href="https://github.com/jes/BangleApps/blob/master/apps/wpmoto/README.md">the README</a> if you want to know more.</p>
<p>Here's what it looks like mounted on my handlebars with a 3d-printed "artificial wrist":</p>
<p><a class="img" href="https://img.incoherency.co.uk/3676"><img src="https://img.incoherency.co.uk/3676/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3677"><img src="https://img.incoherency.co.uk/3677/thumb"></a></p>
<p>It was inspired by the <a href="https://global.beeline.co/">Beeline</a> device which works exactly the same
way, except is more expensive than a Bangle.js and you need to use their proprietary smartphone app to set up the waypoints.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3679"><img src="https://img.incoherency.co.uk/3679/thumb"></a></p>
<p><h2>Test ride</h2></p>
<p>On Tuesday I tried to use Waypointer Moto to navigate to Cheddar Gorge. To cut a long story short I didn't get to
Cheddar Gorge, because I came across a road closure about 2 miles into a windy country road and had to turn back.
But I <i>did</i> discover <a href="https://en.wikipedia.org/wiki/Ebbor_Gorge">Ebbor Gorge</a> just off said windy
road, which I never would have come across if I were following a normal route and is quite a nice walk, so in that
respect it was a great success.</p>
<p>But if you're really keen to get to where you want to go, maybe this isn't the best way to do it.</p>
<p><h2>Development</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/3680"><img src="https://img.incoherency.co.uk/3680/thumb"></a></p>
<p>Waypointer Moto is based on the "Way Pointer" app for Bangle.js, but with a few important changes:</p>
<p><ul>
<li>Use the GPS course instead of the compass to work out the direction of travel, because the compass
is unreliable. Way Pointer uses the compass because Way Pointer is designed for walkers, and the GPS
course is rarely available if you're travelling at walking pace.</li>
<li>Show the status of the GPS fix in the colour of the arrow (red for no fix, yellow for location but no course,
white for all good).</li>
<li>Add an OpenStreetMap integration to the PC-based waypoint editor so that you can click the destination
on the map instead of having to manually type in latitude/longitude coordinates.</li>
</ul></p>
<p>(and a number of less important changes).</p>
<p>As always, developing for Bangle.js was really easy. The only annoying part is adding the integration with
the BangleApps loader, because you need to wait for GitHub actions to rebuild your GitHub Pages every time
you want to see if your change has worked.</p>
<p><h2>Plans</h2></p>
<p>To make Waypointer Moto more useful for situations where you actually really do want to get to where you're going,
I plan to add a "route" mode where you click several waypoints along the route to your destination and it will
automatically step from one waypoint to the next as you approach them.</p>
<p>I also want to add a charge connector to the "artificial wrist" so that the watch can get charged up while it's
in use. I think leaving the screen and GPS on 100% of the time will drain the battery quite quickly. On Tuesday
it drained about 50% in 2h30, so I expect it would only last about 5 hours without charging.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/waypointer-moto.html</link>
   <guid>http://incoherency.co.uk/blog/stories/waypointer-moto.html</guid>
   <pubDate>Thu, 27 Jan 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Measuring motorcycle lean angle with a single accelerometer</title>
   <description><![CDATA[The naive method of measuring motorcycle lean angle with accelerometers is to put a 2-axis accelerometer on the bike and measure
the angle between the x acceleration and the y acceleration. This only works at a standstill. When the bike
is moving, the measured angle would be 0. The purpose of the lean angle is to position the resultant acceleration vector so that it
points from the centre of mass to the contact patch of the tyres, otherwise you will fall over. So how can we measure the lean angle?]]></description>
   <content:encoded><![CDATA[<p>The naive method of measuring motorcycle lean angle with accelerometers is to put a 2-axis accelerometer on the bike and measure
the angle between the <b><i>x</i></b> acceleration and the <b><i>y</i></b> acceleration. This only works at a standstill. When the bike
is moving, the measured angle would be 0. The purpose of the lean angle is to position the resultant acceleration vector so that it
points from the centre of mass to the contact patch of the tyres, otherwise you will fall over. So how can we measure the lean angle?</p>
<p>A motorcycle that's leaning but not cornering looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3667"><img src="https://img.incoherency.co.uk/3667/thumb"></a></p>
<p>The weight of the bike and rider unit is not positioned above the contact patch of the tyres, so the centre of mass is going to
accelerate downwards and the bike will crash.
(Alternatively, the weight and the reaction force from the ground are not aligned, leaving a resultant
torque, so the bike is going to rotate and crash.)</p>
<p>When cornering, we have the centrifugal force counter-acting the lean angle (or, if you prefer, we lean in order to counteract the
centrifugal force):</p>
<p><a class="img" href="https://img.incoherency.co.uk/3669"><img src="https://img.incoherency.co.uk/3669/thumb"></a></p>
<p>(Reaction arrows omitted for brevity).</p>
<p>A 1-axis accelerometer measuring vertically in the bike's frame of reference would see acceleration corresponding to the red
arrow.</p>
<p>Plotting this as a triangle (and turning the forces into accelerations) we get:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3670"><img src="https://img.incoherency.co.uk/3670/thumb"></a></p>
<p>(<b><i>v<sup>2</sup>/r</i></b> unknown, <b><i>g</i></b> assumed constant).</p>
<p>Which we can solve with trigonometry to find the angle:</p>
<p><b><i>cos(&#x3b8;) = g/a<br>
&#x3b8; = acos(g/a)</i></b></p>
<p>In reality this would not work quite so well (even if our accelerometer were perfect, there's no vibration, etc.) because:</p>
<p><ol>
<li>We assume the forces are balanced. In steady state (constant speed, constant radius) this is true, but you need to temporarily unbalance the forces to make the bike lean. We would under-estimate lean when the bike is tipping into a corner and over-estimate when it is standing back up.</li>
<li>We assume a flat road. If the bike is under acceleration in the vertical axis (e.g. cresting a hill) then the effective value of <b><i>g</i></b> for the purposes 
of our triangle is incorrect. We would over-estimate lean in troughs and under-estimate on crests.</li>
</ol>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/accelerometer-lean-angle.html</link>
   <guid>http://incoherency.co.uk/blog/stories/accelerometer-lean-angle.html</guid>
   <pubDate>Mon, 10 Jan 2022 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Advent of Code on my homemade CPU</title>
   <description><![CDATA[This year I've built a 16-bit CPU, along with custom operating system
and programming language. It runs at 1 MHz and has 64 KWords of memory. This December I used it to do Advent of Code.]]></description>
   <content:encoded><![CDATA[<p>This year I've built a 16-bit CPU, along with custom operating system
and programming language. It runs at 1 MHz and has 64 KWords of memory. This December I used it to do Advent of Code.</p>
<p>This is what it looks like:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3655"><img src="https://img.incoherency.co.uk/3655/thumb"></a></p>
<p>It's relatively common to write Advent of Code solutions to <i>run</i> on
limited
hardware. What isn't so common is to <i>develop</i> on the limited hardware,
which is what I've been doing, even to the point of reading the problem statements
and submitting the solutions via a proxy running at the other end of a serial port.
The main difference is that exploratory programming is <i>much</i> more
difficult in an environment where you can't just write a quick Perl script to
learn something about the shape of the problem. Even compiling a small program
takes over a minute.</p>
<p>So far I've completed part 1 of every day except day 24, and part 2 of every day except 15, 22, 23, and 24, although on a couple of days I did resort to using the emulator (~20x faster) when the physical hardware got too frustrating.</p>
<p><h2>Videos</h2></p>
<p>I recorded video of a lot of my attempts. I think the day 6 video is a good one to
start on, because it is relatively short and easy to understand, and I didn't
make too many blunders. You might still prefer to watch on 1.5x speed.</p>
<p><ul>
<li><a href="https://www.youtube.com/watch?v=LrLMMJRUvV4">Watch my day 6 video &raquo;</a></li>
</ul></p>
<p>I enjoyed doing the videos, and a handful of people told me they enjoyed watching
them, so I think I'd like to do more programming videos in the future.</p>
<p><h2>Notable solutions</h2></p>
<p><h3>Day 4: Giant Squid <a href="https://adventofcode.com/2021/day/4">[link]</a></h4></p>
<p>I had already been stung a couple of times by programs that took several minutes
just to parse in the input, so I had the idea that I could 
leave the input somewhere high in memory that nothing else is going
to overwrite, and then just grab the input data straight out
of memory without having to parse it.</p>
<p>So for day 4 I did exactly that. I wrote a program called <a href="https://github.com/jes/aoc2021/blob/master/day4/read.sl">read.sl</a> that read integers from stdin and
wrote them into memory starting at address <tt>0xc000</tt>, and wrote the number of
integers into address <tt>0xbfff</tt>. Then <a href="https://github.com/jes/aoc2021/blob/master/day4/part1.sl">part1.sl</a> looks in <tt>0xbfff</tt> to see how many
integers there are (with an assertion that this number is 2500, so that it can
notice if they are overwritten), and then operates on the input in-place starting
at <tt>0xc000</tt>:</p>
<p><pre><code>var input = 0xc000;
var inputlen = *(0xbfff);
assert(inputlen == 2500, "inputlen = %d\n", [inputlen]);</code></pre></p>
<p>It did work but I think it may have been more trouble than it was worth. It turned
out that parsing the input for this day wasn't all that time-consuming, and it
adds extra stress of trying to make sure you don't do anything that will
silently overwrite your input data. It's a fun idea though, I'm glad I tried it out.</p>
<p><h3>Day 5: Hydrothermal Venture <a href="https://adventofcode.com/2021/day/5">[link]</a></h3></p>
<p>This was the first day where my 64K words of memory presented a problem.
You're operating
on a grid of 1000x1000 points. A million points is too many points to fit in 64K
addresses. Even if you only use 1 bit per point of the grid, that's 62500 points,
leaving only 1500 addresses remaining, which isn't even enough for the kernel, let
alone the program to solve the problem.</p>
<p><a href="https://dartoxia.com/">Ben</a> suggested splitting the input up into a
number of smaller subgrids, and then solving the smaller grids consecutively. This
was a pretty neat solution, and it worked fine. The only caveat was that splitting
the input up into smaller inputs was more complicated than the actual problem! But
that's all good fun. And at least it fits in RAM.
That's exactly the kind of challenge I was looking for when I
started doing Advent of Code on SCAMP.</p>
<p><a href="https://www.simon816.com/">Simon</a> subsequently emailed me
<a href="https://github.com/jes/aoc2021/blob/master/day5/part1-simon.sl">a solution to part 1</a>
that runs in a single pass over the input file by sorting the input lines by
<b><i>x</i></b> coordinate, and only looking at a single <b><i>x</i></b> coordinate at a time and testing which lines overlap in the <b><i>y</i></b> axis at that point
in <b><i>x</i></b>, which is pretty cool. I believe he is the 2nd person
ever to have written a SCAMP program.</p>
<p><h3>Day 13: Transparent Origami <a href="https://adventofcode.com/2021/day/13">[link]</a></h3></p>
<p>I used a hash table as a sparse 2d array of points in this problem. Initially I
wanted to use <tt>sprintf("%d,%d", [&amp;x,&amp;y])</tt> to format the keys for
the hash table, but I found this was running out of memory much more quickly than
expected. I then realised that since my "characters" are 16 bits wide, and the
integers that I'm formatting into the string are also 16 bits wide, I may as well
just write the integer directly into the string! As long as I don't need to
handle 0, this works fine and every integer fits in a single character. It's a much more efficient way to generate hash keys,
because there's no time spent on formatting integers, and less memory wasted on
storing characters. This is a good trick that I used a couple of other times as well.</p>
<p>I made sure that values of 0 don't prematurely terminate the string by adding 1 to
every coordinate:</p>
<p><pre><code>var k = malloc(3);
k[0] = x+1;
k[1] = y+1;
k[2] = 0;</code></pre></p>
<p>After completing day 13 I had a look at my <tt>sprintf()</tt> code and realised that
it initialises the output string to 64 words long, growing it as required. This is
too much in applications that format large numbers of short strings, so I've reduced
the starting length from 64 to 8 words. But just sticking integers directly into
the string is still better.</p>
<p><h3>Day 17: Trick Shot <a href="https://adventofcode.com/2021/day/17">[link]</a></h3></p>
<p>After reading the problem statement I still didn't have a great intuition for what
the trajectories looked like, so instead of writing a program to find the answer,
I first wrote a program that would let me input candidate velocities and see
whether the probe ends up flying over the target, under the target, or hitting
the target.</p>
<p>I discovered quite quickly that once the <b><i>y</i></b> velocities are high enough,
there is only 1 <b><i>x</i></b> velocity that results in hitting the target,
because of the "drag" effect: the <b><i>x</i></b> velocity needs to be reduced to
0 at a time where the <b><i>x</i></b> <i>position</i> is within the target range.</p>
<p>I manually explored the search space and found a convincing-sounding candidate
velocity, submitted it, and it was the correct answer. So I didn't write a part 1
solution at all!</p>
<p><h3>Day 19: Beacon Scanner <a href="https://adventofcode.com/2021/day/19">[link]</a></h3></p>
<p>This was quite a big problem for SCAMP and my solution took several hours to run
even though it was quite well optimised and (I believe) asymptotically optimal.
I used the trick from day 13 of generating hash keys by sticking integers directly
into characters, but went one step further by writing the function to do this
<a href="https://github.com/jes/aoc2021/blob/master/day19/part2.sl#L93">in
assembly language</a> as this function is arguably the "innermost loop" of my
program.</p>
<p><h3>Day 22: Reactor Robot <a href="https://adventofcode.com/2021/day/22">[link]</a></h3></p>
<p>On part 1 you're operating on a 101x101x101 cube: that's just over a million
points, which is too big to fit in memory. I reused the day 5 idea of processing
the input in smaller chunks. I used a bit-set to represent the cube, and processed
it in 4 quarters consecutively, so I only need about 16K words of memory per quarter.</p>
<p>For part 2 even this isn't enough. The correct solution is to use
<a href="https://stackoverflow.com/questions/29528934/coordinate-compression">coordinate compression</a> to remove all <b><i>x</i></b>, <b><i>y</i></b>, and <b><i>z</i></b> values that are not present in the input data, then operate on the much smaller
grid, and then multiply the number in each cell of the smaller grid by the number
of "real" grid cells it represents.</p>
<p>I started working on this but ran out of time before I got it working.</p>
<p><h3>Day 23: Amphipod <a href="https://adventofcode.com/2021/day/23">[link]</a></h3></p>
<p>I solved part 1 by hand in my text editor, without writing any code at all,
which was fun.</p>
<p>I tried to do the same thing for part 2 but gave up and started writing a program
to solve it, but I ran out of time before getting it to work. But I later
learned that <a href="https://github.com/sirgraystar/advent2021/blob/main/bin/day23-2">Owen</a> solved part 2 by hand, so I have had a couple more attempts at this
but still can't do it. I can't even find <i>any</i> way to get all the amphipods
into their correct homes, let alone the <i>shortest</i> way! I read on the subreddit
that there is a 40x difficulty range between the easiest and the hardest
inputs, so maybe I just got unlucky. That's what I'll tell myself.</p>
<p><h2>Problems still to solve</h2></p>
<p><h3>Day 15 part 2</h3></p>
<p>This is a shortest-path search on a 500x500 grid. The grid is derived
deterministically from the 100x100 grid that is used in part 1, so lots of people
on the subreddit are talking about how they cut down their memory usage by not
putting the full grid in memory, but I think this isn't enough. Yes, it is easy
to derive the edge cost for a given edge without storing the full grid, but the
queue for Dijkstra's algorithm is still going to be too big to fit in memory, and
you still need 1 bit per vertex for the visited set so that you don't re-visit
previous points.</p>
<p>My plan is to put my priority queue and my visited set on disk, and use most of RAM
as an LRU cache of disk blocks. My filesystem only supports 65536 blocks, so
everything after the 65536th block is invisible to the filesystem, but my
CompactFlash card is much larger than this. In <a href="https://en.wikipedia.org/wiki/Logical_block_addressing">LBA mode</a>, one 16-bit word sets the upper bits of
the block number, and another sets the lower bits. I can copy and paste the block
IO code from the kernel, but just set the upper bits to some nonzero value, and
then I can treat the CompactFlash card as a random-access block device rather than
having all the overhead of my filesystem.</p>
<p>So once the input file has been read into memory, I'm not using the kernel to do disk IO. The only thing I still need from
the kernel is console output, which is also easy to implement directly in my
program, and then I don't need the kernel <i>at all</i>! This gives me about
48 more blocks' worth of disk cache, at the cost of having to reset the CPU when
the program is done, instead of using <tt>exit()</tt> to return to the shell.</p>
<p>I am concerned that this will be too slow, but it sounds really fun to work on.
I hope to solidify the design on paper and then film a video of my implementation.
I think I'd like to output a 2d progress visualisation to the console,
showing which parts of the grid have already been explored by Dijkstra's algorithm.</p>
<p><h3>Day 22 part 2</h3></p>
<p>I expect that I just need to implement the compressed coordinates version of
my part 1 solution (which I already started),
and go to some effort to minimise the number of bigint
operations.</p>
<p><h3>Day 23 part 2</h3></p>
<p>I think the way to go here is to come up with a sensible representation of
the map and then solve it with Dijkstra's algorithm. I started
doing this, but my representation of the map was too convoluted. There are
actually only 7 places that the amphipods can walk to other than their final destinations,
so treating it as a generic grid that they can freely walk around over-complicates it
quite badly.</p>
<p>Probably I want each of my nodes in the search space to represent the 7 locations
the amphipods can park in, and
a stack for each of the "rooms" that they end up in, and I'll want a function to
calculate the path cost between a pair of points.</p>
<p><h3>Day 24</h3></p>
<p>I tried to solve this by reverse-engineering the input and working out what to
do to make <tt>z == 0</tt>, but only managed to convince myself that it is
<i>impossible</i> unless I can input a single digit with value 15.</p>
<p>I will probably have to read the subreddit carefully and try to pick the good
ideas that other people have posted. <a href="https://github.com/grahamedgecombe/advent-2021/blob/master/src/main/kotlin/com/grahamedgecombe/advent2021/day24/Day24.kt#L202">Graham</a>
views the <tt>z</tt> register as a "stack" encoded in base 26, which is either pushed to or popped from depending on the value of each digit.</p>
<p>This makes sense, and I think the problem with my attempt at solving it by hand is
that I greedily popped at every stage I could, whereas you actually sometimes need
to push even if you can pop, just to ensure that you'll be able to do enough pops
later on.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/advent-of-code-on-scamp.html</link>
   <guid>http://incoherency.co.uk/blog/stories/advent-of-code-on-scamp.html</guid>
   <pubDate>Fri, 31 Dec 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Bubble packing puzzle</title>
   <description><![CDATA[I designed a new puzzle this morning, it's a relatively simple packing puzzle where you have to fit
21 circle-ish pieces into a case.]]></description>
   <content:encoded><![CDATA[<p>I designed a new puzzle this morning, it's a relatively simple packing puzzle where you have to fit
21 circle-ish pieces into a case.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3620"><img src="https://img.incoherency.co.uk/3620/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3622"><img src="https://img.incoherency.co.uk/3622/thumb"></a></p>
<p>It ended up easier to solve than I intended, because the bubble parts were printed in the "solved" configuration, which means
the 3d printing lines all point in the same direction, so it's easy to know which way they should be oriented.</p>
<p>If you want to print it yourself, you can <a class="btn btn-primary" href="https://www.prusaprinters.org/prints/88374-bubble-packing-puzzle">download the print files</a>
from prusaprinters.org.</p>
<p>I haven't used prusaprinters.org before, but so far it seems vastly superior to Thingiverse: you can upload designs on the same day you sign up
instead of having to wait 24 hours to be "approved", and the pages load like they're not served over dial-up.</p>
<p>In comparison to normal jigsaw puzzle geometry, in principle, this puzzle should be harder, because there's no clue
as to the piece orientation (jigsaw pieces can only fit at 4 angles, circles can fit at any angle), and there's
no clue as to which pieces form the outer border.</p>
<p><h2>Design</h2></p>
<p>I started by drawing a "master sketch" in FreeCAD, with a bunch of overlapping circles.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3623"><img src="https://img.incoherency.co.uk/3623/thumb"></a></p>
<p>This sketch is used to model both the pieces and the casing that they fit inside.</p>
<p>For the pieces, I made a flat plate and then raised up the pieces with small gaps in between, in a single part:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3624"><img src="https://img.incoherency.co.uk/3624/thumb"></a></p>
<p>Ideally each piece would be a separate part, but I couldn't work out an efficient way to do that in FreeCAD.</p>
<p>I think a taxonomy of the pieces would identify 4 distinct properties, based on the overlapping
circle shapes:</p>
<p><ol>
<li>pieces that are a complete circle</li>
<li>pieces with all sides concave</li>
<li>pieces with a sharp concave corner</li>
<li>pieces that form the outer border of the shape</li>
</ol></p>
<p>I made sure to include at least one of each type.</p>
<p>I exported the single part with all the pieces as a single STL file and then used the "Z Cut" feature in PrusaSlicer to chop the bottom off,
so that they would all be loose once printed:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3625"><img src="https://img.incoherency.co.uk/3625/thumb"></a></p>
<p>To make the case, I just made a solid block and pocketed in the outline of the master sketch, with a gap around the
outside:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3626"><img src="https://img.incoherency.co.uk/3626/thumb"></a></p>
<p>I left 0.5 mm clearance between the pieces, but this turned out to be too much and they are too loose in the final puzzle.</p>
<p><h2>Improvements</h2></p>
<p>For a second iteration, the following changes should be made:</p>
<p><ul>
<li>the pieces are too loose: the clearance should be reduced</li>
<li>the pieces should be separated from each other and printed in a random orientation</li>
<li>the pieces are too small and fiddly: the entire puzzle should be scaled up by a factor of 2 or 3</li>
</ul></p>
<p>It might be nice to make a larger version in wood using the CNC machine.</p>
<p>Another idea would be a 3-dimensional version, where instead of a bunch of overlapping circles with bits cut out, it would be
a bunch of overlapping spheres with bits cut out.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/bubble-packing.html</link>
   <guid>http://incoherency.co.uk/blog/stories/bubble-packing.html</guid>
   <pubDate>Tue, 23 Nov 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Lightweight and robust quadcopter guards</title>
   <description><![CDATA[I recently built a small quadcopter and have been flying it around the house.
Predictably, I have been crashing into the walls a lot. I wanted to put some rotor guards on
to stop the propellers from scratching things, and I have come up with a 3d-printable rotor guard design that I think is quite elegant.]]></description>
   <content:encoded><![CDATA[<p>I recently built a small quadcopter and have been flying it around the house.
Predictably, I have been <a href="https://www.youtube.com/watch?v=s9mtkFfrP7w">crashing into the walls a lot</a>. I wanted to put some rotor guards on
to stop the propellers from scratching things, and I have come up with a 3d-printable rotor guard design that I think is quite elegant.</p>
<p>Printed in Prusament PC Blend, it looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3615"><img src="https://img.incoherency.co.uk/3615/thumb"></a></p>
<p>I would suggest printing this sort of thing in something like PC, TPU, or Nylon. PETG would probably be fine too.
I know PLA not to be strong enough.</p>
<p>DJI's FPV drones have guards like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3616"><img src="https://img.incoherency.co.uk/3616/thumb"></a></p>
<p>And this is a fine solution for a mass-produced part!</p>
<p>The weakest part of a 3d print is the joins between the layers.
The problem with trying to 3d print the DJI shape is that whatever orientation you print it in, the cross-sectional area for layer
adhesion would be very small at some point or another, which means they would break very easily. You can mitigate this by making
the part thicker, but that would add weight, which is at a premium on a small quadcopter.</p>
<p>My design prints flat and is then folded up later, using only the existing motor-mounting screws for attachment.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3618"><img src="https://img.incoherency.co.uk/3618/thumb"></a><br>
<small>(Image from <a href="https://en.wikipedia.org/wiki/Spherical_geometry">Wikipedia</a>)</small></p>
<p>It makes use of <a href="https://en.wikipedia.org/wiki/Spherical_geometry">spherical geometry</a> to form a triangle
out of 3 angles that sum to more than 180&deg;. Trying to close such a triangle causes the sides to bulge out to fit
a sphere, which gives our shape the 3-dimensional nature we're after. I haven't actually got a solid grasp of the
maths required to calculate the lengths of the sides
so I just made some educated guesses and then refined the shape over a handful of
iterations. (An arc through <b><i>&alpha;</i></b> radians with radius
<b><i>r</i></b> must have length <b><i>&alpha;r</i></b>, but it is more complicated when dealing with real-world parts of non-zero thickness).</p>
<p><a class="img" href="https://img.incoherency.co.uk/3617"><img src="https://img.incoherency.co.uk/3617/thumb"></a></p>
<p>At 0.8mm tall, and printed in PC Blend with the "0.15mm QUALITY" preset in PrusaSlicer, these work out
to only 0.9g each.</p>
<p>Here's a photo of an earlier iteration, printed in PLA, and showing a comparison between the printed part (flat) and installed part (curved):</p>
<p><a class="img" href="https://img.incoherency.co.uk/3612"><img src="https://img.incoherency.co.uk/3612/thumb"></a></p>
<p>By printing it flat, almost all of the stress on the part is contained within the layers, and the little stress that
remains between layers is spread over the surface area of the entire part. This makes it significantly stronger
than a comparable part that is printed in its final form. Another benefit of the flat design is that it is suitable
for laser cutting or CNC routing.</p>
<p>As it stands it's definitely not robust enough when printed in PLA:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3614"><img src="https://img.incoherency.co.uk/3614/thumb"></a></p>
<p>But I've had quite a lot of crashes with the version printed in PC Blend and it is not showing any signs of damage.</p>
<p>Using geometry to force flat parts into lightweight curved shapes seems like quite a powerful idea. I wonder what parts other than quadcopter rotor guards we could make lighter or stronger this way?
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/rotor-guards.html</link>
   <guid>http://incoherency.co.uk/blog/stories/rotor-guards.html</guid>
   <pubDate>Tue, 16 Nov 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made an adjustable loaded die</title>
   <description><![CDATA[I made a loaded die with a tiny servo hidden inside that can move the weight around to change the
distribution of roll probabilities.]]></description>
   <content:encoded><![CDATA[<p>I made a loaded die with a tiny servo hidden inside that can move the weight around to change the
distribution of roll probabilities.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3570"><img src="https://img.incoherency.co.uk/3570/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3576"><img src="https://img.incoherency.co.uk/3576/thumb"></a></p>
<p><h2>Design</h2></p>
<p>A few months ago, <a href="https://www.youtube.com/user/Ruaribush">Ruari</a> had the idea of making a hollow die with a magnet under each face and a ball
bearing inside. Using a larger magnet external to the die, you would attract the ball bearing to
whichever face you wanted to be heaviest, and therefore make an adjustable loaded die.
I did some experiments with that idea but I couldn't get an external magnet to be strong enough
to move the ball around, and I couldn't stop the ball from moving around on its own when shaken.</p>
<p>I got this tiny linear servo off eBay:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3563"><img src="https://img.incoherency.co.uk/3563/thumb"></a></p>
<p>At 20 mm long, it is only slightly larger than a typical d6.</p>
<p>I modelled a die, split into 2 parts, which I could mount the servo inside:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3564"><img src="https://img.incoherency.co.uk/3564/thumb"></a></p>
<p>Three of the holes on the face with number 6 go all the way through. This will be useful later.</p>
<p>I also designed a small platform to mount on the servo horn, to carry the weight:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3567"><img src="https://img.incoherency.co.uk/3567/thumb"></a></p>
<p><h2>Build</h2></p>
<p>With the parts printed out and assembled, and 3 short brass rods turned on the lathe, we get this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3568"><img src="https://img.incoherency.co.uk/3568/thumb"></a></p>
<p>So perhaps now you see how it works. The 3 wires that control the servo are soldered to the back of 3
of the brass pips.</p>
<p>At this point I realised that with the weight mounted on top of the platform, I would be able to drive it
all the way to the face with number 1, but not really get it very close to the face with number 6. I want
to be able to roll 6's on command, so obviously this needs to be the other way around. Right?</p>
<p><a class="img" href="https://img.incoherency.co.uk/3570"><img src="https://img.incoherency.co.uk/3570/thumb"></a></p>
<p>So I put the platform on the other way up before gluing the steel rectangle to it. Now the weight can get
very close to the 6 face. Great success?</p>
<p>Except that's the opposite of what I want! If I want to roll 6's, then I need the weight to be <i>opposite</i>
the 6, so that the 6 faces up when the weight is at the bottom. So it was right in the first place. D'oh! But with the platform upside down, the steel ends up not centered on
the platform, so I can't put the platform back where it was else the steel won't fit inside the cube. Oh well. I'll just
have to roll 1's on command instead of 6's.</p>
<p>At this point I lamented that the brass rods were taking too long to make on the lathe, and <a href="https://whynot.fail/">Dimitris</a> suggested
cutting them out of brass sheet on the CNC machine. I don't know why this didn't occur to me before, but it's much
quicker. I cut out the remaining circles and glued them into the remaining spots for pips:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3571"><img src="https://img.incoherency.co.uk/3571/thumb"></a></p>
<p>I realised another blunder at this point, which is that I managed to stick the pips for the 4 off-centre:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3573"><img src="https://img.incoherency.co.uk/3573/thumb"></a></p>
<p>This is because I centered the pips on the origin in CAD, but the face was not centered on the origin, so the pips
are not centered on the face:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3574"><img src="https://img.incoherency.co.uk/3574/thumb"></a></p>
<p>Never mind.</p>
<p>Now it's time to tidy up the faces to make them look a bit neater, starting with the pips that connect to the
servo, because they stick out the most:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3572"><img src="https://img.incoherency.co.uk/3572/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3575"><img src="https://img.incoherency.co.uk/3575/thumb"></a></p>
<p>And finally, after some sanding and clearcoat, we have this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3576"><img src="https://img.incoherency.co.uk/3576/thumb"></a></p>
<p>Which I'm quite happy with.</p>
<p><h2>Cradle</h2></p>
<p>Now we need a cradle to hold the die in to connect to the conductive pips.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3586"><img src="https://img.incoherency.co.uk/3586/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3587"><img src="https://img.incoherency.co.uk/3587/thumb"></a></p>
<p>The Arduino is running the "Knob" example sketch (File -> Examples -> Servo -> Knob), which reads the value from the potentiometer and sets the corresponding
position on the servo. The wires that need to connect to the servo go to "pogo pins" that stick through the square recess in the cradle. These are sharp spring-loaded contacts
that press against the pips.</p>
<p>I was initially planning to try to sand back the clearcoat on the pips to expose the conductive contacts, but this turned out
not to be necessary because the pogo pins are sharp enough to reach the brass through the lacquer, which leaves small scratches:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3588"><img src="https://img.incoherency.co.uk/3588/thumb"></a></p>
<p><h2>Evaluation</h2></p>
<p><h3>Uniformity</h3></p>
<p>I rolled the die 200 times in each configuration to see how much bias the weight gives the die.</p>
<p>With the weight in the middle:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3583"><img src="https://img.incoherency.co.uk/3583/thumb"></a></p>
<p>It's not exactly uniform here, but it's really not that bad.</p>
<p>There is a slight bias towards the 3 because the 3 is directly opposite 4, which the servo is
mounted on, and the weight of the servo means the 4 ends up at the bottom slightly more often than it should. An easy-ish
solution to this would be to put a counterweight on the back of the 3.</p>
<p>And there is a slight bias towards the 1, I think because the range on the servo is not quite enough to drive the weight
far enough away from the 6. Probably this would be improved by making the die
slightly smaller so that the range of the servo is a larger proportion of the size of the die.</p>
<p>And with the weight close to the 6:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3581"><img src="https://img.incoherency.co.uk/3581/thumb"></a></p>
<p>Moving the weight close to the 6 is certainly effective at making the die roll a 1. It rolls a 1 more than twice as often
as any other number. It rolls a 1 about 40% of the time.</p>
<p><h3>Subtlety</h3></p>
<p>The biggest weakness is that if you shake the die, you can feel the weight inside rattling slightly. Anyone who has ever
used a die before will immediately recognise that there is something going on inside, and at that point the jig is up.</p>
<p>The reason for the rattling is because the servo has some play in it.</p>
<p><a href="https://www.stavros.io/">Stavros</a> suggested using springs to constrain the position of the weight. Alternatively I think you might get away with putting
a strip inside on the 2 and/or 5 face, to press against the weight and stop it from rattling side-to-side. This would
put more strain on the servo while moving the weight, but we don't care.</p>
<p><h3>Practicality</h3></p>
<p>To adjust the position of the weight, you need to hold the die on the cradle. But if you have the sleight of hand skills required
to hold the die on the cradle without anyone noticing, then you might as well just carry 2 dice (one loaded and one not) and swap
them as desired. There's really no need whatsoever for an adjustable loaded die. But I like the idea anyway.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/loaded-dice.html</link>
   <guid>http://incoherency.co.uk/blog/stories/loaded-dice.html</guid>
   <pubDate>Tue, 02 Nov 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Fixing my tablesaw tilt mechanism</title>
   <description><![CDATA[I have a Lumberjack
TS254SE tablesaw. It's not a high-end tablesaw, but it was relatively cheap and it works well enough. Except for the blade tilt mechanism.]]></description>
   <content:encoded><![CDATA[<p>I have a <a href="https://www.lumberjacktools.co.uk/product-lumberjack-ts254se-10--table-saw-with-extending-table-and-legstand-230v-lum00021">Lumberjack
TS254SE</a> tablesaw. It's not a high-end tablesaw, but it was relatively cheap and it works well enough. Except for the blade tilt mechanism.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3538"><img src="https://img.incoherency.co.uk/3538/thumb"></a>
<br><small>(Apologies for the awful lighting in some of these pictures.)</small></p>
<p>You can see a crank handle on the right hand side of the front of the tablesaw. Cranking the handle raises the blade up and down: this feature
works fine. Rotating the wheel that the handle runs inside tilts the top of the blade between 0&deg; and 45&deg; to the left. The tilting
feature <i>never</i> worked satisfactorily. Between about 0&deg; and 15&deg; it was fine, but beyond that the gear teeth would start
skipping unless you wedge the handle sideways, and it would take progressively more effort to get the blade to tilt the further you want it to go.</p>
<p>It recently got so bad that I was avoiding making 45&deg; mitres because I knew it was too much trouble to tilt the blade over.</p>
<p>So I had a look at the mechanism. There is a curved toothed "rack" on the frame of the machine, and a pinion gear on the handle.
I discovered that the gear on the handle was too small. Or, most likely, the designer <i>deliberately</i> spaced the gear teeth apart to stop them
from binding when manufactured with sloppy tolerances, but went too far and now they don't mesh properly.</p>
<p>Upon taking the handle off, I discovered that not only were the teeth on the gear too small to mesh against the rack, but some of them had become
partly broken due to the abuse.</p>
<p>So I designed a quick test gear in FreeCAD, 3d printed a test piece in PLA, checked the mesh of the teeth, and (after getting it the correct
size on the 2nd attempt) superglued it
to the existing gear just to check that it worked. Which it did, but the "draft" mode PLA teeth broke quite quickly.</p>
<p>Having discovered the correct shape of the gear, I then had the problem of how to attach my gear to the handle. I didn't want to 3d print
an entire new handle. I settled for hacksawing the original gear off the end of the handle, facing off the handle on the lathe, and then gluing a new gear to
the end of the handle with epoxy. Unfortunately I hadn't taken any pictures up to this point, but here's what I was left with after hacksawing
the gear off:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3539"><img src="https://img.incoherency.co.uk/3539/thumb"></a> <a class="img" href="https://img.incoherency.co.uk/3532"><img src="https://img.incoherency.co.uk/3532/thumb"></a></p>
<p>My replacement is quite a lot bigger than the original!</p>
<p>The 2nd picture there probably best shows how the mechanism works. The gear is not keyed to the shaft.
Turning the shaft raises/lowers the blade. Turning
the gear engages with the rack, which causes the shaft to be dragged left/right which causes the blade to tilt. Obviously, if the gears don't mesh properly, then
you can't move the shaft left/right so you can't tilt the blade.</p>
<p>For the real version of the part I modelled in some holes to help the epoxy mechanically hold the gear in place:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3531"><img src="https://img.incoherency.co.uk/3531/thumb"></a></p>
<p>Printed this part in Prusament PC Blend, 100% solid (it's entirely made out of perimeters, no infill), and epoxied it to the handle:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3534"><img src="https://img.incoherency.co.uk/3534/thumb"></a></p>
<p>Then it's just a case of installing it on the machine:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3537"><img src="https://img.incoherency.co.uk/3537/thumb"></a></p>
<p>So far it's a great success. I wish I'd done this sooner. In the event that the printed polycarbonate gear breaks I will make a replacement
out of aluminium using the <a href="https://incoherency.co.uk/blog/stories/6040-cnc-grbl-arduino.html">CNC machine</a>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/tablesaw-gear.html</link>
   <guid>http://incoherency.co.uk/blog/stories/tablesaw-gear.html</guid>
   <pubDate>Fri, 01 Oct 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Towards a high-resolution grid of tiny electromagnets</title>
   <description><![CDATA[I'd like to build a high-resolution grid of tiny electromagnets. It would work a lot like an LED matrix display, except instead
of the pixels emitting light, they emit magnetic fields. I have made a small proof-of-concept, but I need help
to learn more physics to improve the strength of the field and the density of the pixels.]]></description>
   <content:encoded><![CDATA[<p>I'd like to build a high-resolution grid of tiny electromagnets. It would work a lot like an LED matrix display, except instead
of the pixels emitting light, they emit magnetic fields. I have made a small proof-of-concept, but I need help
to learn more physics to improve the strength of the field and the density of the pixels.</p>
<p>Here's a video demo of what I have so far. When you watch the video, just use your imagination and visualise the same
sort of thing, except the electromagnets are really small and powerful, and there's maybe 64*64 of them, and they're switched
automatically by a microcontroller instead of by hand.</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/rMbibPDrEkk" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>The idea for this project came from the <a href="https://lichess.org/blog/XlE48hEAACIAQv2F/regium-extraordinary-claims-require-extraordinary-evidence">Regium KickStarter
scam</a>. Regium is an automatic chess board. I actually built <a href="https://incoherency.co.uk/blog/stories/autopatzer.html">an automatic chess board myself</a>. Like most of the commercial
equivalents, my board used a single electromagnet on an X/Y motion stage to move the pieces around. In contrast, Regium claimed to have a high-resolution grid of
tiny electromagnets just underneath the playing surface. This would allow them to move the pieces around silently, to move multiple pieces at once, and to hold all
of the pieces in place while you move the board around so they don't fall over. The only downside is it doesn't exist.</p>
<p>But I love the idea and I want to see how close it is to being possible, so I made a few electromagnets and connected them up in this 3*1 "grid".</p>
<p><a class="img" href="https://img.incoherency.co.uk/3520"><img src="https://img.incoherency.co.uk/3520/thumb"></a></p>
<p><h2>Shortcomings</h2></p>
<p>I wanted to make an actual <i>grid</i> for the proof of concept, even if only 2*2. But I did a handful of small experiments to decide how much wire to put
in one electromagnet, and it turned out I only had enough wire for 3 of them. And I actually ran out before the 3rd one was done, so the
middle one is smaller.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3517"><img src="https://img.incoherency.co.uk/3517/thumb"></a></p>
<p>So in the absence of more wire, a 3*1 grid will have to do.</p>
<p>The electromagnets that I have made so far are both too large and too weak to make an effective chess board. The bobbins are 16mm diameter,
and the housing puts the electromagnets 18mm apart. At 10v the 2 larger coils draw about 350mA and start to get warm if switched on for
a while, so I wouldn't want to put any more current through them. They're barely strong enough to pull the steel ball around, let alone
slide chess pieces across a board.</p>
<p>I did find that the smaller coil, drawing 660mA at 10v, is actually stronger than the larger coils, although it heats up even faster. Maybe
the answer is to get some slightly thicker wire and run it at a higher current.</p>
<p>The core is made out of a mystery steel. I have no idea if it is good, bad, or about average for this purpose.</p>
<p>It may well be that it is not actually possible to make a working automatic chess board this way. You need to have either lots of turns, or
high current, to create a strong magnetic field, and both of those place physical limits on how small you can make the electromagnets. It's
quite possible that the achievable resolution is just not good enough.</p>
<p><h2>Questions</h2></p>
<p>I think this project would benefit from knowing the answers to some/all of the following questions. If you know
the answers, or know someone who does, please email me: <a href="mailto:james@incoherency.co.uk">james@incoherency.co.uk</a>.</p>
<p><ol>
<li>How do we quantify how effective a candidate material would be to make the core out of? I want to be able to compare any 2 different materials, to find out which one is better & by how much.</li>
<li>What is the best material to make the core out of?</li>
<li>What is the best wire diameter? You can fit more windings in the same space if the diameter is lower, but you can't put as much current through it.</li>
<li>Short of adding more turns (makes it larger), or more current (needs thicker wire, which makes it larger), how can we make the electromagnets stronger?</li>
<li>How much of a difference does the diameter of the core make? We want it small to increase the resolution.</li>
<li>Does adding turns via more height actually help, or does it just serve to shift the centre of the magnetic field further from the surface?</li>
<li>Would making the core encompass the outside of the coil be advantageous, disadvantageous, or irrelevant? Note that we want the field to extend away from the surface, we aren't just looking for the highest possible density at points immediately close to the coil.</li>
<li>How high a frequency do we need to switch the coils on/off if we want the field to stay relatively constant?</li>
<li>Would adding a capacitor to each coil, to form a low-pass filter, help with multiplexing them?</li>
<li>What are some potential applications for this technology beyond an automatic chess board?</li>
</ol></p>
<p>Commercial electromagnets tend to have the core surrounding the coil except for a small gap at the top, and they also tend not to be excessively
tall.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3524"><img src="https://img.incoherency.co.uk/3524/thumb"></a>
<br><small>(Pic from <a href="https://www.adafruit.com/product/3872">Adafruit</a>. The coil is underneath the black seal; the core is the shiny part.)</small></p>
<p>However, commercial electromagnets are normally aiming to <i>grab</i> things that they contact. They would rather have a very
concentrated field right next to the surface of the electromagnet, whereas we would rather have the field extend
further away from the electromagnet, even at the expense of field strength immediately adjacent to it.
So I'm cautious of imitating the common commercial designs because I think they may be counterproductive for our application.</p>
<p><h2>How I made it</h2></p>
<p>I 3d printed the end caps:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3523"><img src="https://img.incoherency.co.uk/3523/thumb"></a></p>
<p>They have a 16mm outer diameter, and the centre is a tight fit on a 4mm core.</p>
<p>I chucked some 4mm mystery steel rod stock in the lathe, slid on a couple of end caps, taped down the starting end of the wire,
and ran the lathe, using my fingers to guide the wire onto the core.
Here's a clip of that process:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/A656rSRIZpk" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<br><small>(Yeah, I know, the lathe is dirty and I should clean it).</small></p>
<p>Having wound the entire coil, I wrapped the windings in tape to stop them coming loose, and then cut the coil free
of the rod stock with an angle grinder. I think if I were to make more of these I would cut the cores to length ahead-of-time,
and come up with some alternative way of holding them in the lathe while winding the coil. There's too much risk of damaging
the wire with the grinder otherwise.</p>
<p>Since I had no natural reference for the relative positions of the 2 end caps, the 3 coils ended up slightly different
lengths, so when I 3d printed the housing I compensated for this in CAD:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3516"><img src="https://img.incoherency.co.uk/3516/thumb"></a></p>
<p>You can see the left hole is shorter than the other 2, which are also not exactly equal. Having printed
the housing, we have these parts:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3517"><img src="https://img.incoherency.co.uk/3517/thumb"></a></p>
<p>I then dropped in each coil, soldered to copper wires at top and bottom, and wrapped it in sellotape to keep them in place, and
to allow the ball to roll around more easily:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3518"><img src="https://img.incoherency.co.uk/3518/thumb"></a> <a class="img" href="https://img.incoherency.co.uk/3519"><img src="https://img.incoherency.co.uk/3519/thumb"></a></p>
<p>The bottoms of the coils all share a common ground. I would use a similar plan if I were making a "real" grid rather than a
straight line. There would be a wire at the top for each column and a wire at the bottom for each row. To energise a single coil,
you have to connect that coil's row (for example) to 10v, and its
column to ground. Then the only coil that has a complete circuit is the one at the intersection of the selected row and
column. The benefit of this is that as the grid size grows, you only need to be able to switch <i>O(n)</i> connections
to address an arbitrary coil in an <i>n*n</i> grid.</p>
<p>Finally, I connected some buttons to the coils so that I can power them up independently:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3520"><img src="https://img.incoherency.co.uk/3520/thumb"></a></p>
<p><h2>Maglev chess</h2></p>
<p>While talking about this project, <a href="https://github.com/pwr22/">Peter</a> suggested that "maglev chess" would be a
fun idea. You wouldn't even need it to be automated in any way, I think just the sensation of manually moving chess
pieces around on top of a surface that makes them levitate would be fun. I don't know enough physics to know the best way to do
it, but I think you'd want the centre of each square to repel the pieces, and the edges of the square to repel the pieces even
more strongly, so that the only place for the piece to go is up in the air.</p>
<p>You also need to make sure that the pieces don't fall over, either by putting the magnets at the top so that gravity works
for you (but then you need the repulsion to be much stronger), or by having multiple poles on the bottom so that the
piece can't tip in any direction.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/electromagnet-grid.html</link>
   <guid>http://incoherency.co.uk/blog/stories/electromagnet-grid.html</guid>
   <pubDate>Tue, 21 Sep 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Choozi for Bangle.js</title>
   <description><![CDATA[Do you know Chwazi? It is an Android app that chooses a person at random.
Everyone puts in their finger and it selects one at random to highlight. It's
useful for example if you're playing a board game and need to select a person
at random.]]></description>
   <content:encoded><![CDATA[<p>Do you know Chwazi? It is an Android app that chooses a person at random.
Everyone puts in their finger and it selects one at random to highlight. It's
useful for example if you're playing a board game and need to select a person
at random.</p>
<p>Chwazi:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3510"><img src="https://img.incoherency.co.uk/3510/thumb"></a>
<br><small>(photo from <a href="https://la-matatena.com/chwazi-una-app-para-saber-quien-comienza/">la-matatena.com</a>)</small></p>
<p>Well, I finally thought of a useful app to make for my <a href="https://incoherency.co.uk/blog/stories/banglejs-first-impressions.html">Bangle.js watch</a>.
It's called "Choozi". Here's a demonstration:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/4cqOLNM5ei8" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>The watch doesn't have a multitouch screen, and even if it did it would be a bit unwieldy asking multiple people
all to put one finger on the watch screen. So instead it just distributes segments in a circle around the outside
of the screen. The intention is that the group would be seated in a circle, and it would be clear which position
corresponds to which person.</p>
<p>I am quite pleased with the animations. They are actually pushing the device pretty far. That's as fast as it
can render those animations, there's no kind of delay or frame rate calculations at all, it's just drawing each
frame one after the other as fast as it can.</p>
<p>The Bangle.js development process is slightly strange. You first write your app in the <a href="https://www.espruino.com/ide/">Espruino IDE</a>
(using Chromium because Firefox doesn't support Web Bluetooth) and test it out on the watch by uploading it to RAM via Bluetooth.
Once you're happy with it, and you want to add your app
to the menu so that you can use it again, or to the official <a href="https://espruino.github.io/BangleApps/">Bangle.js apps loader</a> so
that other people can download it, you need to make a clone of the
<tt>BangleApps</tt> repo, make a directory for your app, copy and paste your code out of the web IDE and into a source file
in that directory, and then modify <tt>apps.json</tt> to include your app. And then use the <a href="https://www.espruino.com/Image+Converter">Espruino
Image Converter</a> to turn your logo into an Espruino graphic suitable for use on the watch. Make sure you output as "Image String"
instead of "Image Object", otherwise it won't work and won't tell you why.</p>
<p>I have submitted <a href="https://github.com/espruino/BangleApps/pull/806">a pull request</a> to get Choozi
added to the official loader. If it's accepted
then you should be able to install it on to your watch from there. In the mean time, if you want it, you can install it
from <a href="https://jes.github.io/BangleApps/#choozi">my fork of BangleApps loader</a> instead.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/choozi.html</link>
   <guid>http://incoherency.co.uk/blog/stories/choozi.html</guid>
   <pubDate>Tue, 14 Sep 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Approximating Lenna with a neural net</title>
   <description><![CDATA[Last night, inspired by a comment on HN about creating
images with randomised neural nets by mapping inputs (x,y) to outputs (r,g,b), I spent some time trying to
train a small neural net to approximate Lenna, the famous image
processing test input. The outputs are quite interesting to look at, but don't approximate Lenna very well. But I don't know
anything about machine learning, so I think you could do much better than I managed.]]></description>
   <content:encoded><![CDATA[<p>Last night, inspired by a <a href="https://news.ycombinator.com/item?id=28448626">comment on HN</a> about creating
images with randomised neural nets by mapping inputs <i>(x,y)</i> to outputs <i>(r,g,b)</i>, I spent some time trying to
train a small neural net to approximate <a href="https://en.wikipedia.org/wiki/Lenna">Lenna</a>, the famous image
processing test input. The outputs are quite interesting to look at, but don't approximate Lenna very well. But I don't know
anything about machine learning, so I think you could do much better than I managed.</p>
<p>If you don't know what a neural network is, maybe start with <a href="https://en.wikipedia.org/wiki/Neural_network">the Wikipedia page</a>.</p>
<p>Here's a diagram of the kind of network I was using (mostly a bit bigger than this, but not a <i>lot</i> bigger because
training on CPU is slow):</p>
<p><a class="img" href="https://img.incoherency.co.uk/3505"><img src="https://img.incoherency.co.uk/3505/thumb"></a></p>
<p>Here's about the best I came up with, after about 3 hours of training, next to the training image (can you tell which is which?):</p>
<p><a class="img" href="https://img.incoherency.co.uk/3486"><img src="https://img.incoherency.co.uk/3486/thumb"></a> <a class="img" href="https://img.incoherency.co.uk/3487"><img src="https://img.incoherency.co.uk/3487/thumb"></a></p>
<p>I had rather hoped for a bit better than this, although the generated image does have quite an interesting aesthetic in its own right.</p>
<p>Here's a video showing how the output improves as training proceeds:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/OmhIrA8RF84" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p><h2>More outputs</h2></p>
<p>Here are some other interesting-looking outputs, not as good as the above.
Unfortunately I didn't save the parameters used because I'm not a real scientist.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3502"><img src="https://img.incoherency.co.uk/3502/thumb"></a> <a class="img" href="https://img.incoherency.co.uk/3501"><img src="https://img.incoherency.co.uk/3501/thumb"></a> <a class="img" href="https://img.incoherency.co.uk/3500"><img src="https://img.incoherency.co.uk/3500/thumb"></a> <a class="img" href="https://img.incoherency.co.uk/3499"><img src="https://img.incoherency.co.uk/3499/thumb"></a> <a class="img" href="https://img.incoherency.co.uk/3494"><img src="https://img.incoherency.co.uk/3494/thumb"></a> <a class="img" href="https://img.incoherency.co.uk/3490"><img src="https://img.incoherency.co.uk/3490/thumb"></a></p>
<p>You can <i>almost</i> make out an outline of a face in a couple of them. If you squint.</p>
<p>These pictures remind me of the kind of nondescript, inoffensive artwork you sometimes find in hotels. It obviously looks like <i>something</i>, but
it doesn't look like enough of anything that anybody could possibly be put off by it.</p>
<p>Some of the states from early on in the training, with less detail, are also reminiscent of <a href="https://www.omgubuntu.co.uk/every-ubuntu-default-wallpaper">old Ubuntu desktop wallpapers</a> from
around Ubuntu 10.10 to 13.10.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3503"><img src="https://img.incoherency.co.uk/3503/thumb"></a> <a class="img" href="https://img.incoherency.co.uk/3504"><img src="https://img.incoherency.co.uk/3504/thumb"></a>
<br><small>(left: early state from neural net of Lenna; right: Ubuntu 13.10 default wallpaper)</small></p>
<p><h2>How</h2></p>
<p>I used the <a href="https://metacpan.org/pod/AI::FANN">AI::FANN</a> perl module, which I think was
last updated in 2009, so I imagine the state of the art is now substantially better (probably you'd
use <a href="https://www.tensorflow.org/">TensorFlow</a> if you knew what you were doing?), but
I found AI::FANN easy to get started with, and it entertained me for an evening.</p>
<p>The input image's <i>(x,y)</i> coordinates are scaled to fit in the interval <i>[-1,1]</i>. The
<i>(r,g,b)</i> values are scaled to fit in <i>[0,1]</i>. (I tried various options and this seemed
to work best, but... not an expert, don't know why).</p>
<p>We then create a training set consisting of <i>(x,y) => (r,g,b)</i> for every pixel of the input image,
and initialise a neural network with 2 input nodes (x and y), 3 output nodes (r, g, and b), and some number
of hidden nodes in some number of hidden layers that we can play with to see what difference it makes.
I found I had best results with
3 hidden layers, each with fewer than 20 hidden nodes.</p>
<p>We then run <a href="https://en.wikipedia.org/wiki/Rprop">Rprop</a> training over and over again to make
the neural network better approximate the function described by the training data, and periodically
save the current state so that it can be turned into a video later.</p>
<p>If you want you can <a href="https://gist.github.com/jes/aff9bf4b09e8ac75d78691d9d9403fec">use the perl script
I was playing with</a> - but it's not really meant for general
consumption.</p>
<p>And to turn a directory full of generated images into a video, I used:</p>
<p><pre><code>$ ffmpeg -r 25 -i %04d.png -c:v libx264 -vf scale=800x800 out.mp4</code></pre></p>
<p><h2>Why</h2></p>
<p>I just did this to see what would happen, but if it worked a bit better I can think of a couple of
interesting applications.</p>
<p>Firstly, it might be an interesting way to lossily-compress images down to almost arbitrarily-small sizes, in a
way that retains detail <i>differently</i> (if not necessarily "better") than traditional lossy compression algorithms.</p>
<p>Secondly, it can be used to upscale
images in a way that might look more natural than normal interpolation algorithms, because the
neural net (presumably) encodes some more abstract information about the shapes in the image, rather
than the pixel values.</p>
<p><h2>Potential improvements</h2></p>
<p>I did try reducing the image to black-and-white to see if reducing the amount of work the network
had to do would make it train more quickly, but it didn't seem to make a lot of difference. It
generated the same kind of images, but in black-and-white.</p>
<p>Also, since the output images are clearly lacking <i>so much</i> detail of the input image, I tried
downscaling the input image, on the basis that having fewer training inputs would make the
training run more quickly. And it did help, but obviously that's not a general solution.</p>
<p>The neural net has to be quite small because I'm training it on the CPU and it is slow. It would
be interesting to see if it would be much better with much larger networks trained on a GPU.
I don't know if a larger network would actually help that much. I still think my network with <i>3*15*3</i> hidden
nodes could do a much better approximation than what I'm seeing, so I think the real limitation is in the
training method, which GPU speed would also presumably help with.</p>
<p>Finally, I think it would be interesting to try training it with a genetic algorithm instead of with backpropagation.
You'd maintain a population of candidate weightings for the network, and at each generation you
evaluate each candidate for fitness, and then breed the best handful together by repeatedly selecting weights from 2 "parents" to produce
1 "child", with a small amount of mutation (and maybe even some backpropogation training!), to go into the next
generation's population.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/lenna-neural-net.html</link>
   <guid>http://incoherency.co.uk/blog/stories/lenna-neural-net.html</guid>
   <pubDate>Wed, 08 Sep 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The case for SCAMP</title>
   <description><![CDATA[All of the SCAMP hardware is now mounted properly inside the case, with no Arduino or breadboard required.
I'm now well into the "long tail" of tasks on this project, where it takes increasingly large amounts of time to
produce increasingly small improvements.]]></description>
   <content:encoded><![CDATA[<p>All of the SCAMP hardware is now mounted properly inside the case, with no Arduino or breadboard required.
I'm now well into the "long tail" of tasks on this project, where it takes increasingly large amounts of time to
produce increasingly small improvements.</p>
<p>I think I'm <i>almost</i> ready to bolt the box together and not open it again. I just need some way to
transfer files between the SCAMP and my Linux PC, which would be either a removable CompactFlash card or a
secondary serial port. There is already some hardware provision for both of these, so it might just be as
simple as plugging a second 8250 into the serial card and connecting up the pins on its front panel.</p>
<p>Here are some pictures of the computer:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3468"><img src="https://img.incoherency.co.uk/3468/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3484"><img src="https://img.incoherency.co.uk/3484/thumb"></a></p>
<p>All of the electronics are mounted to the base, with a small panel at the back holding the power socket and at
the front holding the power/reset buttons and VGA console. Then the wooden box can drop over the card cage and bolt
down to it. The wooden parts are made of 15mm "Russian birch" plywood. I believe this is sold as "Baltic birch" in
other parts of the world. It's great quality stuff, I like using it.</p>
<p>I'm quite pleased with the joints on the box:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3453"><img src="https://img.incoherency.co.uk/3453/thumb"></a></p>
<p>I made all of these parts on the CNC machine, with a deliberate slight overhang on the joints, and then planed them flush by hand after gluing.</p>
<p>And here's a short video showing the current state:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/-PAeJ6gzgXI" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>(In the video the serial port output doesn't work at first, and I suggest that the VGA console might not have been ready. But on further
reflection this can't be it, because the VGA console is already drawing a cursor. The output actually starts working after the point
that the kernel re-initialises the UART, which suggests that when the bootloader tried to initialise the UART it didn't
work. I don't know why that would happen. Possible problems ahead...)</p>
<p><h2>Front panel</h2></p>
<p>I was originally planning to put the clock and power/reset buttons on a dedicated card plugged into the backplane,
but given that I only have 2 spare slots, I decided I'd rather not waste one. So power and reset buttons are on
a panel mounted to the case, and the clock is super-glued to the backplane.</p>
<p>It might have been nice if I'd got 2 buttons that were both the same size.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3472"><img src="https://img.incoherency.co.uk/3472/thumb"></a></p>
<p>I really like the effect of the power button lighting up when it's switched on. I'm also
quite fond of the text engraving. I did this with a 2mm single-flute down-cutting end mill</p>
<p>The VGA console is attached to the back of the front panel with a 3d-printed bracket.
It is extremely close to the power supply. You may not believe it from the photograph,
but it actually doesn't touch - but it can do if you press on the front panel, so I have prevented it from shorting
out by sticking some insulating tape to the power supply.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3477"><img src="https://img.incoherency.co.uk/3477/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3478"><img src="https://img.incoherency.co.uk/3478/thumb"></a></p>
<p>You can see I have very skilfully managed to stick the mounting screw out the back of the panel. Well, at least I didn't
stick it out the front! The rest of the case is only held together with glued joints, but I decided to screw this
one because I might need to take it off to gain better access to the stuff mounted on the back.</p>
<p>Because there's not a lot of room in this part of the case for the VGA console PCB, I went through a handful
of 3d-printed iterations of the panel before cutting it out on the CNC machine.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3473"><img src="https://img.incoherency.co.uk/3473/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3474"><img src="https://img.incoherency.co.uk/3474/thumb"></a></p>
<p><h2>Clock</h2></p>
<p>Don't laugh: the clock is mounted to the backplane upside-down with super glue.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3475"><img src="https://img.incoherency.co.uk/3475/thumb"></a></p>
<p>This is kind of hacky but it'll do for now. If it doesn't cause any problems then it'll probably stay like
this permanently. I think the most likely problem is that I'll bash it while trying to drop the case on,
and short one of the pins.</p>
<p>It is just a 1 MHz crystal oscillator. It seems like a great invention, I wonder why anyone ever uses a bare crystal.</p>
<p><h2>Power supply</h2></p>
<p>The power-supply is screwed to the bottom panel of the wooden case:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3479"><img src="https://img.incoherency.co.uk/3479/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/3485"><img src="https://img.incoherency.co.uk/3485/thumb"></a></p>
<p>The AC power socket in the back has an integrated switch and fuse. Unfortunately the fuse holder is an unusual size and I couldn't find a fuse that would
fit, and since UK power plugs have integrated fuses anyway, I decided it was fine (arguably <i>best</i>) to bypass the fuse in the power
socket.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3481"><img src="https://img.incoherency.co.uk/3481/thumb"></a></p>
<p>I'm not sure if the capacitor across the 5v output is doing any good. I don't expect it is doing any harm.</p>
<p><h2>Wiring</h2></p>
<p>We need to run a few wires from the backplane out to the front panel. Namely:</p>
<p><ul>
<li>Power & ground</li>
<li>Reset</li>
<li>TX & RX of serial console</li>
</ul></p>
<p><a class="img" href="https://img.incoherency.co.uk/3482"><img src="https://img.incoherency.co.uk/3482/thumb"></a></p>
<p>It's reasonably tidy, and running all the wires down one side means I have plenty of room to work on it if I unscrew the front
panel and cut off the cable ties - I can then bring the whole panel around to the side of the machine with a good amount of slack
in the wires.</p>
<p><h2>CompactFlash</h2></p>
<p>I previously thought my original CompactFlash interface was going to be adequate, but after wiring up the new front panel,
mounting the power supply inside the case, and moving the clock source to the middle of the backplane, it didn't work any more.
Bummer. I'm not sure if it didn't like the new clock placement, or didn't like being so close to the power supply, or something
else. Don't know. This is kind of the "dark magic" side of electronics for me.</p>
<p>So I made a 2nd revision of the CompactFlash interface, this time putting 74HC245 "bus transceivers" on the data lines between
the card and the bus, as recommended by <a href="https://github.com/PickledDog/rc-cfcard">PickledDog</a>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3471"><img src="https://img.incoherency.co.uk/3471/thumb"></a></p>
<p>It seems to be an <i>improvement</i>, in the sense that it now works with both of my CF cards where the previous one only
ever worked with one, and it now works up to 1.2 MHz (although there is other instability at that speed).</p>
<p>But it didn't magically make the computer start working on its own, so there is obviously something else about
the CompactFlash interface that is a bit sensitive. I found that moving it to the middle of the bus made a big improvement. I
don't really know why. I wish I understood this stuff better. My mental model is that a conductor is at either 0v or 5v, and voltage
changes propagate infinite distance instantaneously. It's frustrating that this is not a sufficient model for even my puny computer
at my puny clock speed.</p>
<p><h2>Other</h2></p>
<p>SCAMP has been accepted into the <a href="https://www.homebrewcpuring.org/">Homebrew CPU ring</a>. I think I'm expected to
put the webring home/previous/next/random buttons on the project page, but since the project page is currently just a
<tt>README.md</tt> on github, I've settled for adding a link to the Homebrew CPU ring in the "Resources" section.</p>
<p>I've been reading <a href="https://www.forth.com/starting-forth/">Starting FORTH</a>, a FORTH tutorial from I think 1981.
You can read the PDF online. FORTH is a fascinating language, but I still don't think I'm completely sold. FORTH code
quickly gets completely unintelligible if you don't break it down into a large number of small "words", but the requirement
to find a word to describe each part means you end up with lots of words that all sound the same but do slightly different
things. I also found it to be slightly inconsistent with the Reverse Polish Notation. For example, <tt>:</tt> lets you define
a new word, but it has to come <i>before</i> the word you're defining, because it operates on the input
stream rather than the stack. But all words can do that: any word can take its argument from the input stream instead of
the stack. You just have to develop a mental model in which it is clear where the arguments for any given word are going
to come from, but I'm not there yet.</p>
<p>I read that to truly understand FORTH you need to implement your own, and implementing FORTH sounds like a much
more compelling proposition than actually writing programs in it. So I think it's fairly likely I'll be making
a FORTH system for SCAMP, and from there it's fairly likely that the edit-compile-test loop in FORTH will be
substantially faster than in SLANG, so if I get on with it I may end up using FORTH for some of Advent of Code, which might be fun.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/scamp-case.html</link>
   <guid>http://incoherency.co.uk/blog/stories/scamp-case.html</guid>
   <pubDate>Thu, 02 Sep 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Play with SCAMP from the comfort of your browser</title>
   <description><![CDATA[Today I ported the SCAMP emulator to the web, using emscripten
to compile C to WebAssembly, and Xterm.js to provide the terminal
emulator.]]></description>
   <content:encoded><![CDATA[<p>Today I ported the SCAMP emulator to the web, using <a href="https://emscripten.org/">emscripten</a>
to compile C to WebAssembly, and <a href="https://xtermjs.org/">Xterm.js</a> to provide the terminal
emulator.</p>
<p>You can play with it here: <a href="https://incoherency.co.uk/scamp/" class="btn btn-primary">SCAMP Emulator &raquo;</a>.</p>
<p><a href="https://incoherency.co.uk/scamp/"><img src="https://img.incoherency.co.uk/3454/thumb"></a></p>
<p>Fun things for you to do with the emulator include playing <a href="https://incoherency.co.uk/blog/stories/hamurabi.html">Hamurabi</a>, writing
a "Hello, world" program in <a href="https://incoherency.co.uk/blog/stories/slang.html">SLANG</a> using <a href="https://incoherency.co.uk/blog/stories/kilo.html">kilo</a>, finding new and interesting ways to
cause kernel panics, and fixing whatever bug is causing half the files that should be in <tt>/src/</tt> to go missing.</p>
<p>(If you actually do manage to cause a kernel panic, and it's <i>not</i> one of: deleting files from <tt>/proc/</tt>,
filling up the disk, tinkering with kernel memory - then please email me and let's try and fix it!).</p>
<p>The disk image is not persistent, which means you lose all your work as soon as you close the tab, and there's also no
way to upload or download files. Maybe that'll come later, maybe not. There's also no documentation, so... good luck.</p>
<p>This was actually my 2nd attempt at putting together a web emulator. The first time I gave up because I couldn't think of a quick and easy
way to share the C code between the CLI emulator and the web-based version, because the CLI version's profiling and debugging hooks
get in the way. This time I decided to just copy and paste the code and throw away the parts I don't want.</p>
<p>You might think that having 2 near-identical copies of the same code is distasteful: I agree. But I'd rather
have an ugly program in the computer than an elegant one in my head. Perfect is the enemy of good, etc.
Maybe one day I'll tidy it all up so that the common parts are shared. (Ha, good joke).</p>
<p><h2>Emscripten</h2></p>
<p>Setting up emscripten is much easier than you might expect. You can just copy and paste ~5 commands from the
<a href="https://emscripten.org/docs/getting_started/downloads.html">getting started</a> guide, and then you're ready to go.
After that, I didn't bother with the rest of the official guide, I instead followed a
<a href="https://developer.mozilla.org/en-US/docs/WebAssembly/C_to_wasm">much shorter introduction from Mozilla</a>.</p>
<p>I've been really impressed with emscripten. It seems that at every turn, if it's <i>possible</i> for emscripten to do
some magic to make your life easier, then it does it. It even does a little bit of magic that <i>doesn't</i> seem possible.
I'd like to use emscripten more often.</p>
<p><h2>Xterm.js</h2></p>
<p>Xterm.js is also really good, but its <a href="https://xtermjs.org/docs/">documentation</a> leaves a lot to be desired. (Yeah, yeah, that's a bit rich, I know).</p>
<p>It has the kind of documentation that you get if you think comprehensive auto-generated descriptions of internal interfaces
is preferable to short sections of typical example usage.</p>
<p>Apart from the auto-generated interface documentation, you're in good hands if you want 4000 words on
<a href="https://xtermjs.org/docs/guides/hooks/">Parser Hooks & Terminal Sequences</a>, but if you want to know how
to resize the terminal to 80x25, you have to read the source and figure it out yourself.</p>
<p>(Protip: <tt>term.resize(80,25)</tt>. If this is documented then I certainly couldn't find it).</p>
<p>Apart from the documentation, Xterm.js is actually quite easy to use. Just make a <tt>&lt;div id="terminal" /&gt;</tt>,
<tt>let term = new Terminal(); term.open(document.getElementById('terminal')</tt>, hook <tt>onKey()</tt> to find out about user input, and
<tt>term.write(...)</tt> to provide output. It pretty much handles being a terminal emulator exactly the way you'd expect.</p>
<p><h2>Building the emulator</h2></p>
<p>Emulating the CPU itself is mostly simple. I just simulate all the changes to the control signals on a negative clock edge,
and then a positive clock edge, and then repeat.
The annoying parts are interfacing with the terminal, populating
the disk contents, and populating the boot ROM and microcode ROM contents.</p>
<p>To populate the boot ROM and microcode ROM, I wrote <a href="https://github.com/jes/scamp-cpu/blob/master/web/hex2c">a Perl script</a>
to convert the ROM files into C source files that contain their contents. I initially tried to use the same technique for the disk
image, but at 32 megabytes it was too big to compile on my laptop and <tt>emcc</tt> ran out of memory trying to compile it.</p>
<p>I subsequently learnt that <tt>emcc</tt> has an option, <tt>--preload-file</tt>, that allows you to include existing files inside
the emscripten environment. This turned out to be perfect: just compile with <tt>--preload-file os.disk</tt>
and then read the disk contents from <tt>os.disk</tt> at runtime using normal C filesystem interaction. This is really incredible
technology. I expected emscripten to compile C code to WebAssembly, I didn't expect it to provide a simulated operating system!</p>
<p>My complete command line is:</p>
<p><pre><code>emcc -o scamp.js scamp.c ucode.c rom.c --preload-file os.disk -s WASM=1 -O3 -s NO_EXIT_RUNTIME=1 -s EXPORTED_RUNTIME_METHODS=['ccall'] -s ALLOW_MEMORY_GROWTH=1</code></pre></p>
<p>I think <tt>NO_EXIT_RUNTIME</tt> means your program maintains its state even after <tt>main()</tt> returns. Putting <tt>ccall</tt> in <tt>EXPORTED_RUNTIME_METHODS</tt>
lets you call C functions from JavaScript, and <tt>ALLOW_MEMORY_GROWTH</tt> is required because I want to allocate 32 megabytes of memory to store the disk image.
(I actually load the disk image with <tt>mmap()</tt> because that's how I did it for the CLI emulator, and amazingly this "just works" thanks
to yet more incredible emscripten technology).</p>
<p>Part of the point of using emscripten rather than writing the emulator in Javascript is that I don't trust Javascript to be
sufficiently performant to run the CPU at 1 MHz. To that end, I want to keep Javascript out of the loop as much as possible, so my "please run a clock
cycle" function takes an argument that says how many clock cycles to run, and that way we don't need to initiate 1 million function calls per
second from Javascript:</p>
<p><pre><code>EMSCRIPTEN_KEEPALIVE
char *tick(int N, char *input) {</code></pre></p>
<p>(<tt>EMSCRIPTEN_KEEPALIVE</tt> prevents the compiler from optimising the function out on the basis that it is never called - we need it because we'll be calling it from Javascript).</p>
<p>The idea of <tt>tick()</tt> is that console input characters are passed as an argument, and console output is returned. This is kind of weird and unpleasant,
but it does the trick. Calling this function from Javascript looks like:</p>
<p><pre><code>let pending_output = ccall('tick', 'string', ['number', 'string'], [10000, pending_input]);</code></pre></p>
<p>The <tt>ccall()</tt> arguments are:</p>
<p><ul>
<li>the name of the function to call (<tt>tick</tt>)</li>
<li>the return type of the function (some more emscripten magic turns the <tt>char*</tt> into a string for javascript - incredible)</li>
<li>the types of the arguments (even <i>more</i> magic turns the javascript strings into <tt>char*</tt> for C!)</li>
<li>the values for the arguments (run for 10000 clock cycles, append <tt>pending_input</tt> to the UART input buffer)</li>
</ul></p>
<p>Having spent most of this year writing low-level code for SCAMP, where the computer can't even work out if you've passed the correct
number of arguments to a function, it blows my mind that emscripten can just magically turn Javascript types into
the appropriate C types for the specific function you're calling, and it all just works. Very impressive stuff.</p>
<p>To get IO to/from Xterm.js, keypresses and text output are sent between the main web page and the web worker using <tt>postMessage()</tt>.</p>
<p><h2>Web stuff</h2></p>
<p><a href="https://charlie.ht/">Charlie</a> complained that the page took a long time to load over a mobile connection. This was almost entirely down to having to load
the 32 megabyte disk image, but since the disk is almost completely empty, it seems a bit wasteful. I asked nginx to compress it:</p>
<p><pre><code>location /scamp/scamp.data {
    gzip on;
    gzip_types application/octet-stream;
}</code></pre></p>
<p>
And that solved the problem: it now only transfers 362 kilobytes for the disk image, almost 100x improvement.</p>
<p><tt>kilo</tt> originally used Ctrl-S to save the file, but this collides with <a href="https://en.wikipedia.org/wiki/Software_flow_control">software flow control</a>,
which means I can't save anything if I'm using the real hardware via a USB serial cable in <a href="https://www.gnu.org/software/screen/">screen</a>.
So I changed it to Ctrl-W to <i>write</i> the file. Unfortunately Ctrl-W collides with "please close my tab and don't let the page intercept the keypress" in Firefox,
which means it's impossible to save anything in the web-based emulator. So now I've changed it to
Ctrl-O, which matches <a href="https://en.wikipedia.org/wiki/GNU_nano">nano</a> and stands for "output".
I can't wait to find out what sort of UI Ctrl-O is going to interact poorly with.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/scamp-web-emulator.html</link>
   <guid>http://incoherency.co.uk/blog/stories/scamp-web-emulator.html</guid>
   <pubDate>Mon, 09 Aug 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Porting Hamurabi to SCAMP</title>
   <description><![CDATA[That's right! 1968's most exciting video game release is coming to 2021's most disappointing CPU architecture.
Hamurabi
is a single-player text-based game in which you play the leader of ancient Sumeria for
10 years. Each year, you decide how much land to buy or sell, how much food to feed to the population, and how much land to plant with seeds. Occasionally
a plague comes along and kills half the population, or rats eat some of the harvest. Land values, harvest yields, and immigration rates
fluctuate unpredictably. At the end of the 10 years (if you haven't been forcibly removed from office already) your performance is evaluated.]]></description>
   <content:encoded><![CDATA[<p>That's right! 1968's most exciting video game release is coming to <a href="https://github.com/jes/scamp-cpu">2021's most disappointing CPU architecture</a>.
<a href="https://en.wikipedia.org/wiki/Hamurabi_(video_game)">Hamurabi</a>
is a single-player text-based game in which you play the leader of ancient <a href="https://en.wikipedia.org/wiki/Sumer">Sumeria</a> for
10 years. Each year, you decide how much land to buy or sell, how much food to feed to the population, and how much land to plant with seeds. Occasionally
a plague comes along and kills half the population, or rats eat some of the harvest. Land values, harvest yields, and immigration rates
fluctuate unpredictably. At the end of the 10 years (if you haven't been forcibly removed from office already) your performance is evaluated.</p>
<p>Here's a short demo of inaccurate play:</p>
<p><script id="asciicast-2Gac5yhxAAuF6CsoNg24YagIx" src="https://asciinema.org/a/2Gac5yhxAAuF6CsoNg24YagIx.js" async></script></p>
<p>It's actually pretty easy to win the game with the highest praise almost every time if you know how it works.
Perhaps I'll write up "How to win at Hamurabi" at some point.</p>
<p>If you want, you can play the game online in a handful of places. Probably the most authentic experience is <a href="https://playold.games/play-game/hamurabi/play/">the
one on "playold.games"</a>. It appears to be a DOS port of the game running in the browser in a javascript DOSbox. Or if you <i>really</i> want, you can
<a href="https://github.com/jes/scamp-cpu">clone the SCAMP repo</a>, work out how to build everything, and run <tt>hamurabi</tt> in the SCAMP emulator. Email
me if you can't figure it out.</p>
<p><h2>Porting Hamurabi</h2></p>
<p>The original game was apparently written in <a href="https://en.wikipedia.org/wiki/FOCAL_(programming_language)">FOCAL</a>, although at
that time it was called "King of Sumeria" or "The Sumer Game". Its roots can be traced back further, however, to
<a href="https://en.wikipedia.org/wiki/The_Sumerian_Game">The Sumerian Game</a> from 1964, so it's not entirely obvious to me where Hamurabi
can be said to have started. I'd be interested to look at the FOCAL source code, but I couldn't find it. Fortunately, the game has had
many ports over the years.</p>
<p>The earliest source code I found was <a href="https://www.atariarchives.org/basicgames/showpage.php?page=79">this low-res BASIC listing</a> from
the book <a href="https://www.atariarchives.org/basicgames/index.php">BASIC Computer Games</a> published in 1978, so that's what I ported to SCAMP,
bugs and all. Of course, that's not to say I didn't introduce extra bugs of my own.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3449"><img src="https://img.incoherency.co.uk/3449/thumb"></a></p>
<p>The full source of my port is in <a href="https://github.com/jes/scamp-cpu/blob/master/sys/hamurabi.sl">sys/hamurabi.sl</a> in the SCAMP git repo.</p>
<p><h3>Arithmetic</h3></p>
<p>I was surprised to find that such an old game appears to make extensive use of (presumably) floating point arithmetic, e.g.:</p>
<p><pre><code>552 D=P-C: IF D&gt;.45*P THEN 560</code></pre></p>
<p>I don't yet have any fractional number support on either my CPU or programming language, so I converted these calculations into pure integer form for <a href="https://incoherency.co.uk/blog/stories/slang.html">SLANG</a>:</p>
<p><pre><code>if (mul(D,100) &gt; mul(45,P)) {</code></pre></p>
<p><small>(The CPU doesn't natively support multiplication, so neither does the programming language - I considered implementing infix multiplication as
syntactic sugar, but decided the explicit function call is fun and quirky. To be honest it was touch and go whether the language would even have a non-buggy
magnitude comparison operator...)</small></p>
<p><h3>Input</h3></p>
<p>At first reading I thought the game systematically omitted question marks on questions:</p>
<p><pre><code>320 PRINT "HOW MANY ACRES DO YOU WISH TO BUY";
321 INPUT Q: IF Q<0 THEN 850</code></pre></p>
<p>This presents a real dilemma: I don't want my port to deviate from historical accuracy, but I also don't want to ask questions without question marks.</p>
<p>Fortunately, I later came across a screenshot from the game which clearly shows question marks on questions:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3450"><img src="https://img.incoherency.co.uk/3450/thumb"></a><br><small>(From <a href="https://en.wikipedia.org/wiki/Hamurabi_(video_game)">Wikipedia</a>)</small></p>
<p>So I have surmised that the <tt>INPUT</tt> statement in BASIC inserts its own question mark, and also that the trailing semi-colon after
a <tt>PRINT</tt> statement suppresses a trailing end-line character.</p>
<p>That said, the screenshot clearly shows "O MIGHTY MASTER" wording after "THINK AGAIN", which the BASIC listing definitely doesn't have, so who knows?
Maybe the BASIC version actually didn't have question marks.</p>
<p><h3>Comments</h3></p>
<p>The BASIC source code is very sparsely commented, and the comments don't even address my biggest questions. I would have appreciated
comments explaining how the calculations are meant to work, and what the single-letter variable names are meant to represent. Instead, these
things have to be derived by working backwards from the impact they have on the text output. But at least the immigration calculation has this:</p>
<p><pre><code>532 REM *** LET'S HAVE SOME BABIES
533 I=INT(C*(20*A+S)/P/100+1)</code></pre></p>
<p><h3>Control flow</h3></p>
<p><tt>IF</tt> statements in this dialect of BASIC appear to function more like a conditional jump than a normal if statement, in that they
take a line number as a branch target, rather than a block of code to conditionally execute. This makes the control flow quite hard to follow.
The language also doesn't appear to support named functions, although it thankfully does have a <tt>RETURN</tt> statement, so some form of
proto-subroutine is possible.</p>
<p>Example:</p>
<p><pre><code>410 PRINT "HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE";
411 INPUT Q
412 IF Q&lt;0 THEN 850
418 REM *** TRYING TO USE MORE GRAIN THAN IS IN SILOS?
420 IF Q&lt;=S THEN 430
421 GOSUB 710
422 GOTO 410
430 S=S-Q: C=1: PRINT
...
710 PRINT "HAMURABI:  THINK AGAIN. YOU HAVE ONLY"
711 PRINT S;"BUSHELS OF GRAIN.  NOW THEN,"
712 RETURN</code></pre></p>
<p>Also note that there is nothing at line 410 to mark it as the start of a loop body, or at 710 to draw attention to the fact that this is
the entry point of a subroutine. You just have to know. In my opinion, the SLANG port is substantially easier to follow, despite my
efforts to mimic the original coding style.</p>
<p><pre><code>while (1) {
    printf("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE",0);
    Q=input();
    # *** TRYING TO USE MORE GRAIN THAN IS IN SILOS?
    if (Q <= S) break;
    thinkgrain();
};
S=S-Q; C=1;
printf("\n",0);
...
thinkgrain = func() {
    printf("HAMURABI:  THINK AGAIN. YOU HAVE ONLY\n",0);
    printf("%d BUSHELS OF GRAIN.  NOW THEN,\n",[S]);
};</code></pre></p>
<p><small>(The <tt>IF Q&lt;0 THEN 850</tt> test is moved into the <tt>input()</tt> function because it's the same on every input - if you try to
input a negative number the game tells you "HAMURABI:&nbsp;&nbsp;I CANNOT DO WHAT YOU WISH. GET YOURSELF ANOTHER STEWARD!!!!!" and you lose)</small></p>
<p><h3>Random numbers</h3></p>
<p>Random numbers are an important part of the game. They create uncertainty about the future which mimics the real-life conditions that the
game is trying to simulate. I don't know how good the BASIC random number generator is, but I know that the SCAMP one is awful. This is
the first program I've written for SCAMP that needed random numbers, so I wrote this:</p>
<p><pre><code>var randstate = 0x5a7f;
var rand = func() {
    randstate = mul(randstate, 17) + 0x2e7;
    return randstate;
};</code></pre></p>
<p>The seed is the same every time, so it is easy to learn what the land prices and harvest yields are going to be, when there will be
a plague, and so on, but it's a start. The form of the RNG (<i>X<sub>n+1</sub> = (a X<sub>n</sub> + c) mod m</i>) is a
<a href="https://en.wikipedia.org/wiki/Linear_congruential_generator">linear congruential generator</a>, but the constants (<i>a=17</i>, <i>c=0x2e7</i>, and implicitly <i>m=0xffff</i>), are chosen
by guessing instead of for their good properties. I definitely want a better RNG for SCAMP eventually, but this is adequate to make the game
work for now.</p>
<p>I've been thinking a bit about how I might seed the RNG so that it isn't the same every time. It would be quite easy to have the kernel
count loop iterations between booting up and the first keyboard input, maybe that's the best way to seed it.</p>
<p><h2>Other SCAMP stuff</h2></p>
<p><h3>Case</h3></p>
<p>I have made a start on the wooden case. Here's some photos of the card cage inside the case, with no cards installed:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3452"><img src="https://img.incoherency.co.uk/3452/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3451"><img src="https://img.incoherency.co.uk/3451/thumb"></a></p>
<p>I still have some sanding to do to tidy up the joints, but it is roughly what I wanted. Removing the domed nuts at the top allows
most of the case to lift off, allowing access to the back and sides of the card cage. The card cage is more permanently bolted to the
base piece, which also holds the power socket and power supply.</p>
<p>Originally I was going to put the power switch, reset switch, and clock on a PCB in the card cage, but given that that would only
leave 1 spare slot to experiment with, I think I'd rather put them on a separate panel mounted to the bottom of the case, and bodge-wired
to the backplane, to leave a 2nd slot free for expansion.</p>
<p><h3>Clock</h3></p>
<p>I experimented with the <a href="https://incoherency.co.uk/blog/tags/rc2014.html">RC2014</a> clock card to find out how high I could clock SCAMP without anything
going wrong. I was disappointed to find that the limit is about 1 MHz. The next step up available on the RC2014 clock is 1.2 MHz, and at
that speed I couldn't get the CompactFlash card to work. I did attempt Bill Shen's <a href="https://groups.google.com/g/rc2014-z80/c/LmvGa6PZNhQ/m/H8jrbp86AQAJ">suggestion</a> of putting 100 Ohm resistors on the data lines and an RC filter on <tt>IORD</tt>, but it didn't appear to make any difference. So I've given
up for now and I'm just going to tolerate running it at 1 MHz. It would be nice to go faster, but I can always revisit it at a later date. Getting
it finished is more important. <a href="http://www.thelifeadventuristic.co.uk/">Rory</a> suggested adding a pull-up/-down resistor to every
line on the bus to help the levels transition more quickly. I haven't yet tried this.</p>
<p>Apart from the CompactFlash card, everything else seems to work up to at least 2.5 MHz, and after that point text output stops working, and I
can tell from looking at the lights that the CPU isn't working properly either. But if I can fix the CompactFlash problem then 2.5 MHz should
be within easy reach. I then don't know which part is making it fall off the rails above 2.5 MHz, and don't know exactly how I'd go about
debugging it. Maybe I'd need to attach a pretty wide logic analyser to the bus and see if I can work out what is happening?</p>
<p><h3>Other games</h3></p>
<p>Tetris would be good, to complete the <a href="https://www.nand2tetris.org/">nand2tetris</a> theme. Snake might also work,
although it would have to be played on the 80x25 text terminal.
I think <a href="https://en.wikipedia.org/wiki/Colossal_Cave_Adventure">Colossal Cave Adventure</a> is an almost mandatory port.
And a <a href="https://en.wikipedia.org/wiki/Z-machine">Z-machine</a> implementation would open up a great wealth of other text adventures
for free.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/hamurabi.html</link>
   <guid>http://incoherency.co.uk/blog/stories/hamurabi.html</guid>
   <pubDate>Fri, 06 Aug 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Book Review: Every Tool's a Hammer</title>
   <description><![CDATA[I recently read Every Tool's a Hammer
by Adam Savage.
I am somewhat hesitant to call this post a "review" because it's much closer to a selection of quotations from the book
presented without comment. But I think the book is good. And I have enjoyed some of this year's book reviews
on Astral Codex Ten. And if I say this is a review then it's a review.]]></description>
   <content:encoded><![CDATA[<p>I recently read <a href="https://www.goodreads.com/book/show/43319933-every-tool-s-a-hammer">Every Tool's a Hammer</a>
by <a href="https://en.wikipedia.org/wiki/Adam_Savage">Adam Savage</a>.
I am somewhat hesitant to call this post a "review" because it's much closer to a selection of quotations from the book
presented without comment. But I think the book is good. And I have enjoyed some of this year's book reviews
on <a href="https://astralcodexten.substack.com/">Astral Codex Ten</a>. And if I say this is a review then it's a review.</p>
<p>If you read this <i>review</i> and enjoy it but think you now no longer have anything to gain from reading the book,
then know that precisely the opposite is the case! I am barely scratching the surface of the
material the book covers. It is a tome of great wisdom.</p>
<p><h2>Adam Savage</h2></p>
<p>If you only know Adam Savage from <a href="https://en.wikipedia.org/wiki/MythBusters">MythBusters</a>, then you
may be under the impression (as I used to be) that his expertise is primarily as a TV presenter, and only secondarily as any kind
of builder of things. This couldn't be further from the truth. In the book, he describes himself thus:</p>
<p><blockquote>I'm a generalist in my creative output and a wannabe polymath in how I organize my life.</blockquote></p>
<p><blockquote>My talent lies not in my mastery of individual skills, at which I'm almost universally mediocre, but rather in the combination of those skills into a toolbox of problem solving that serves me in every area of my life.</blockquote></p>
<p>(And if this sounds interesting to you, you may also enjoy <a href="https://www.goodreads.com/book/show/41795733-range">Range: Why Generalists Triumph in a Specialized World</a>).</p>
<p>There are probably hundreds to thousands of hours of Adam Savage, talking and making things, available on his
<a href="https://www.youtube.com/channel/UCiDJtJKMICpb9B1qf7qjEOA">Tested</a> YouTube channel.
If you want to watch some but don't know where to start, I might recommend <a href="https://www.youtube.com/watch?v=-xWGRVL-ExA">his machine vise build</a> or <a href="https://www.youtube.com/watch?v=7COvFaFTAy4&t=16m33s">this segment on imposter syndrome</a>.</p>
<p><h2>The "Maker" label</h2></p>
<p>The book mentions a common aversion to the "maker" label: that of considering oneself <i>not good enough</i> to
call oneself a maker. He brings up an example of someone he spoke to at a Maker Faire who said "I don't make, I code":</p>
<p><blockquote>The list of exceptions people invent to place themselves on the outside of the club of makers is long and, to me, totally infuriating. Because the people who do that to themselves&mdash;or more likely, the people who TELL them that&mdash;are flat wrong.</blockquote></p>
<p>And goes on (convincingly) to argue that any act of creation is an act of making, no matter what kind of thing you're making.</p>
<p>There is another take on the aversion to "maker", not directly addressed in the book: some might be wary of adopting the label out of a fear
that "maker" is just a word for a substandard practitioner of a more specific craft.
But I don't think that's quite right. Anyone who makes <i>anything</i> is a maker. The perception of "makers" sometimes doing subpar work is more down to the aggressive
sharing in the maker community. You see more <a href="http://paulgraham.com/early.html">early work</a> from those who describe themselves
as makers than from those who follow more formal paths into craftsmanship. This should be encouraged, not squashed.</p>
<p><h2>Philosophy</h2></p>
<p>The book contains a lot of good insights on the philosophy of making, and why we do it. And more importantly, why
we sometimes <i>don't</i> do it, instead running into barriers that we've erected inside our own heads.
I was hooked from the introduction alone. If you read the book and the introduction doesn't excite you, then you
probably needn't bother reading the rest. But it probably will.</p>
<p>Now I have quotations to present without comment.</p>
<p>On culture:</p>
<p><blockquote>Whenever we're driven to reach out and create something from nothing, whether it's something physical like a chair, or more temporal and ethereal, like a poem, we're contributing something of ourselves to the world. We're taking our experience and filtering it through our words or our hands, or our voices or our bodies, and we're putting something in the culture that didn't exist before. In fact, we're not putting what we make into the culture, what we make IS the culture.</blockquote></p>
<p>On permission:</p>
<p><blockquote>[This book] is also a permission slip. The permission slip is from me, to you. It says you have permission to grab hold of the things you're interested in, that fascinate you, and to dive deeper into them to see where they lead you. You might not need that permission. If that's the case, good for you! Go forth and do awesome things. But I have needed that permission many times in my life. And whenever I found it, it helped me uncover secrets about myself and about the world I live in. It made me better as a man, as a maker, and as a human being.</blockquote></p>
<p>On vulnerability:</p>
<p><blockquote>As the things we make give us power and insight, at the same time they also render us vulnerable. Our obsessions can teach us about who we are, and who we want to
be, but they can also expose us. They can expose our weirdness and our insecurities, our ignorances and our deficiencies.</blockquote></p>
<p>On obsession:</p>
<p><blockquote>We can't even countenance the idea that someone could be obsessed with something and be of sound mind. That is a shame, because when it comes to creativity, when it comes to making things, when it comes to success at anything, obsession is often the seed of real excellence.</blockquote></p>
<p>On bullshitting:</p>
<p><blockquote>Embrace the noun (Maker, Painter, Writer, Designer) by sharing with the world evidence that you've been living the verb (making, painting, writing, designing). Just don't be a bore, and definitely don't believe your own bullshit. Believe me everyone can tell the difference between someone who just talks the talk and someone who can walk the walk.</blockquote></p>
<p>On sharing:</p>
<p>The book covers a time that Adam was trying to find work in Manhattan special effects companies, and found the staff to be insular, unwilling to share, as if they
considered the sharing of their knowledge to be a threat to their livelihood. This was in
stark contrast to the working environment he later found in San Francisco, where not only were the staff much more willing to freely share knowledge with one
another, but the company owner (<a href="https://en.wikipedia.org/wiki/Jamie_Hyneman">Jamie Hyneman</a>, cohost on MythBusters) gave the staff free usage of the workshop during their
down time to work on whatever they wanted.</p>
<p><blockquote>It's up to you to decide what you're going to do with all the knowledge you accumulate. Are you going to hide it? Are you going to pretend that you alighted upon all your insights by divine providence? Or are you going to share what you have learned? Are you going to open yourself up to the people in your orbit and show them who you are, what you love, what you've made, what you know, who's helped you, and what you plan to do with all this to make the world a better place to live?</blockquote></p>
<p>Related (but only obliquely covered in the book):
telling others about your work increases your <a href="https://www.codusoperandi.com/posts/increasing-your-luck-surface-area">luck surface area</a>, so you should do it even
if you don't care about improving anyone else's lot.</p>
<p><h2>Productivity</h2></p>
<p>Adam writes lists to keep track of things. Todo lists, parts lists, shopping lists, and so on. Initially he would simply cross something off the list once he
was done with it, but he found checkboxes to be superior. With the checkbox system, you draw an empty square next to each item of the list, and colour in the square
when that item is done. This leaves the writing still legible, and also gives the opportunity to leave a square half-coloured-in when the job is half done.</p>
<p><blockquote>The elegance and effectiveness of this planning system floored me, particularly when it came to evaluating the status of a project the further along it
went. The value of a list is that it frees you up to think more creatively, by defining a project's scope and scale for you on the page, so your brain doesn't have to hold on to so much information. The beauty of a checkbox is that it does the same thing with regard to progress, allowing you to monitor the status of your project, without having to mentally keep track of everything.</blockquote></p>
<p>Adam's workshop philosophy is "see everything, reach everything".</p>
<p>On drawers:</p>
<p><blockquote>Let me tell you my philosophy about drawers: F*CK DRAWERS! Drawers are where stuff goes to die. Drawers lure you into a false sense of security by "helping" you put things away and making the shop look "cleaner". But really, by putting stuff out of sight, they remove it from your visual field.</blockquote></p>
<p>He refers to the "see everything" half of this phrase as the "visual cacophony". The "reach everything" part is "first-order retrievability". He tells a story of
having earnt some money and bought himself an expensive toolbox set, only to find that it didn't suit his style of working:</p>
<p><blockquote>I gave the Kennedy stack a good four years to prove itself, but eventually, as a natural enemy of the visual cacophony, I had to get rid of it. In its place I built a rolling, five-runged , five-foot-tall ladder rack with twenty holes drilled into each rung big enough to accommodate the handles of every tool I'd kept in the Kennedy stack. I literally turned the storage drawers inside out. Each tool has a place that's fairly obvious, they are all in sight, and I can get to any of them five times faster than it took me just to figure out which drawer they used to be in.</blockquote></p>
<p>On sweeping up every day:</p>
<p><blockquote>Sweeping up every day and putting away my tools is a conversation between present me and future me. It is present me acknowledging that future me always likes to keep the momentum of a project going, and that having to look for a tool or walk across the shop to get one in the middle of a critical phase can slow down the creative process enough to be an existential threat to the project as a whole.</blockquote></p>
<p><h2>Prescription</h2></p>
<p>Read it for the wisdom on maker philosophy. Also enjoy the discussions on productivity, workshop organisation, safe and efficient tool usage, snippets of Adam Savage's
life story, and the surprisingly long section on all the different types of glue. And tolerate the distractions into film buffery and cosplay.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/every-tools-a-hammer.html</link>
   <guid>http://incoherency.co.uk/blog/stories/every-tools-a-hammer.html</guid>
   <pubDate>Mon, 28 Jun 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>SCAMP update</title>
   <description><![CDATA[I've made a bit more progress on my SCAMP CPU. I/O performance is
improved significantly since last time, the CompactFlash card now lives on a PCB instead of a breadboard, I'm
using a real (ish) serial console instead of an FTDI cable, and I have a more
permanent power supply instead of the bench power supply.]]></description>
   <content:encoded><![CDATA[<p>I've made a bit more progress on my SCAMP CPU. I/O performance is
improved significantly since <a href="https://incoherency.co.uk/blog/stories/scamp-1mhz.html">last time</a>, the CompactFlash card now lives on a PCB instead of a breadboard, I'm
using a real (ish) serial console instead of an FTDI cable, and I have a more
permanent power supply instead of the bench power supply.</p>
<p>Here's a video I recorded showing the computer booting up, and writing,
compiling, and running a short program:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/4sBB0iD6XvI" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>I would like to share more stuff via video, but I'm not very good at it, and
still feel silly while talking to the camera on my own.</p>
<p><h2>Performance</h2></p>
<p>It previously took about 19 seconds to get from reset to the shell, which
is now down to 6 seconds, mainly because of the CompactFlash I/O
improvements in the kernel. I wasn't specifically looking to optimise the
boot time. 19 seconds is fine. A faster boot is just a happy side effect.</p>
<p><h3>I/O</h3></p>
<p>I have finally got around to rewriting the CompactFlash I/O inner loops
<a href="https://github.com/jes/scamp-cpu/blob/a63c95115629937da5ca55c02dfb751664dbc322/kernel/cf.sl#L82">in assembly language</a>.</p>
<p>It's probably beyond obvious to real assembly language programmers, but I found
that unrolling the loop was a big improvement. My first attempt was more like:</p>
<p><pre><code>loop:
    in x, CFDATAREG # 5 cycles (read data from device)
    ld (r3++), x    # 8 cycles (write to buffer)
    dec r0          # 5 cycles (loop overhead)
    jnz loop        # 4 cycles (loop overhead)</code></pre></p>
<p>You can see that it only spends 13 out of 22 cycles (59%) on instructions
that are actually copying data. The rest is loop overhead. With the loop
unrolled, that's now 104 out of 113 cycles (92%). We're copying 256 words
each time we read a block from the card, so the total cycle count
has reduced from about 5600 to about 3600 (-35%), just by unrolling the loop
into groups of 8.</p>
<p>I found that the <tt>memcpy()</tt> on every disk I/O operation was also
quite a significant bottleneck. That also benefited from loop
unrolling, using the <a href="https://en.wikipedia.org/wiki/Duff%27s_device">Duff's device</a> trick of jumping part way into a
multiple-of-N loop to copy non-multiple-of-N blocks of data. It's not
particularly easy to read, but you can <a href="https://github.com/jes/scamp-cpu/blob/a63c95115629937da5ca55c02dfb751664dbc322/kernel/util.sl#L98">read my memcpy() implementation here</a>. I found calculating the jump target too inconvenient, so I did it by indexing into an array of
loop offsets instead. It ain't stupid if it works.</p>
<p><h3>Text editor</h3></p>
<p>The text editor was originally grabbing characters from the console via
the kernel, using the <tt>read()</tt> call on the input file descriptor.
This worked OK, except arrow keys didn't work. Arrow keys work by sending
an escape character, followed by a "<tt>[</tt>", followed by a letter
to indicate which arrow it is. Left arrow is the 3-character sequence
"<tt>^[ [ D</tt>".</p>
<p>The reason arrow keys didn't work is that with the serial line running at
115200 baud, and the CPU at 1 MHz, we only get about 86 clock cycles to
process each incoming character before another one is here. The overhead of
grabbing each character via the kernel was just way too high. I tried
slowing the serial line down to 9600 baud, but it still wasn't enough to
handle arrow keys.</p>
<p>Even aside from that, I found the text editor almost unusably slow.
It redraws parts of the
display on every keypress and this was taking too long. I <a href="https://incoherency.co.uk/blog/stories/slang.html">profiled this in the emulator</a> and found that it was spending
about 480,000 cycles between accepting a character of input and being ready
to accept the next character. At 1 MHz, that translates to 480 ms, which
means if you type any faster than 25 wpm, it's going to start dropping
characters. I like to type at more like 120 wpm, so that's no bueno.</p>
<p>Most of the 480,000 cycles were spent on providing output via the kernel,
rather than on calculating anything interesting.</p>
<p>So to solve these problems, I rewrote the text editor's text input and
output code
in assembly language, inside the text editor. It now interacts with the
UART directly instead of using the kernel. This isn't ideal, because for example
if I ever gain support for multiple console devices, the text editor
will need to handle that separately instead of getting it for free via
the kernel. But that seems unlikely anyway.</p>
<p>The editor now takes only 78,000 cycles to process an input character,
which means it's good for about 150 wpm, which I was initially delighted
with. However I eventually realised that this gets worse at the end of
the line. It redraws the entire line every time the line changes, so
when there are more characters it takes longer. At the end of the line this
rises to about 213,000 cycles, or 56 wpm, which is still a bit on the slow
side. So there's probably more work to do here. Probably I just rewrite
the line-drawing code in assembly language.</p>
<p><h3>Compiler</h3></p>
<p>From watching the video, you might be surprised that it takes about a
minute to compile a single-line program. This is probably my next avenue
for optimisation, because compiling programs is one of the things I
definitely want to be able to do with this computer. (My ultimate goal
is to use this computer to solve as much as possible of this year's
<a href="https://adventofcode.com/">Advent of Code</a>).</p>
<p>I'm not completely sure what it is wasting so much time on. Originally,
compiling programs was slow because it re-compiled the entire standard
library every time. But the library is now cached as an (approximation of
an) object file that can just be dumped at the start of the generated
binary. The pattern on the lights suggests that compilation is very I/O bound.
I need to profile it and find out.</p>
<p><h2>CompactFlash PCB</h2></p>
<p>I have now got a PCB to hold the CompactFlash card:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3419"><img src="https://img.incoherency.co.uk/3419/thumb"></a></p>
<p>The long wire that's not connected to anything is meant to indicate the internal
card's "busy" status with an LED on the front, but I decided to rip off the pad
that it was soldered to, so it doesn't work at the moment.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3416"><img src="https://img.incoherency.co.uk/3416/thumb"></a></p>
<p>And it contains provision for a removable "external" card which can be inserted
through the front panel. There is no software support for this yet (and
in fact I may have done something wrong on the PCB, because with a
CompactFlash card plugged in to the 2nd slot the computer won't even boot correctly; need to investigate).</p>
<p><h2>Serial console</h2></p>
<p>I'm currently using the <a href="https://www.tindie.com/products/maccasoft/vga-serial-terminal-kit-for-rc2014/">RC2014 VGA Serial Terminal</a> to
connect SCAMP to a keyboard and monitor, but this isn't completely
ideal because a.) I'd like to put this back in my RC2014, and b.) the pins
aren't labelled, so it is quite tricky to make sure I am plugging
everything into the correct ones.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3418"><img src="https://img.incoherency.co.uk/3418/thumb"></a></p>
<p>The creator of this board, <a href="https://www.maccasoft.com/en/electronics/vga-interface-for-rc2014-computer/">Marco Maccaferri</a>, also designed a
similar board that is a standalone VGA serial terminal, rather than plugging into the RC2014 backplane. Unfortunately he no longer offers
kits for sale, but they <a href="https://connect.gi/terminal.htm">are
available from a website called connect.gi</a>. I found the seller to be friendly and helpful.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3417"><img src="https://img.incoherency.co.uk/3417/thumb"></a></p>
<p>I have received my standalone VGA serial terminal, but I decided to solder
the 3.3v regulator (not pictured) on backwards so now it doesn't work. I then broke one of the legs while trying to desolder it, but hopefully once my replacement regulator arrives I will
be able to switch to the standalone board.</p>
<p><h2>Power supply</h2></p>
<p>I bought this power supply ages ago but hadn't got around to testing it
until this week:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3411"><img src="https://img.incoherency.co.uk/3411/thumb"></a></p>
<p>It is a 5v 10A DC power supply. It turns out that 10 amps is about 9.5 amps more than I need,
but at least it's futureproof.</p>
<p>One strange quirk of SCAMP is that it doesn't work properly at 5.0v, it
needs more like 4.8v. I previously believed that this was just down to
miscalibration of the voltage display on my bench power supply, but now I believe it is
because I have not made any effort to meet the spec required for
interfacing with the CompactFlash card. It seems to get stuck waiting for the card
while trying to read the kernel off the disk if running at 5.0v. But for the time
being, I don't care what the problem is. I just run it at 4.8v and it's fine.</p>
<p>The power supply has a trimpot on it to let you adjust the output voltage,
but I found that even at the lowest setting it was barely below 5.0v,
and the computer wouldn't boot. The trimpot was variable from 0 Ohms to 1 kOhm, and I found that the lowest output voltage was achieved with the trimpot
set to the highest resistance. So the solution is clear: I just need to
replace the trimpot with one that goes higher.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3412"><img src="https://img.incoherency.co.uk/3412/thumb"></a></p>
<p>I replaced the 1 kOhm trimpot with a 2 kOhm trimpot that I already had in stock, and was able to set
it to 4.8v and the computer boots! Great success.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3410"><img src="https://img.incoherency.co.uk/3410/thumb"></a></p>
<p>Don't tell anyone I'm not qualified service personnel.</p>
<p><h2>Bug fixes</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/3409"><img src="https://img.incoherency.co.uk/3409/thumb"></a></p>
<p>One of the bugs last time was that the text output from the bootloader and
kernel startup was missing a load of characters, because they tried to
output bytes faster than the serial line could take them. I've now made
all of the serial output code check the UART status before writing
anything, so that problem is gone.</p>
<p>Another bug was that typing a space would sometimes insert a nul character
instead of a space. I do not know what was causing this problem. It has
gone away now that I'm not stuffing bytes into the UART faster than it
can transmit them, so maybe I was running into a strange edge case of the
UART? Not sure.</p>
<p>Another bug-in-waiting was that my "32 MB" CompactFlash card only has
62,270 blocks instead of 65,536. The SCAMP filesystem assumes that it always
has 65,536 blocks to play with, so this is no good, and would eventually lead to
block contents disappearing into a black hole. My current "solution"
to this problem is to <a href="https://github.com/jes/scamp-cpu/commit/a63c95115629937da5ca55c02dfb751664dbc322">mark the missing blocks as "used"</a> so
that they can never be allocated for use. This isn't an ideal mechanism
because it makes resizing the filesystem non-trivial (there is nothing to
indicate which blocks are actually used and which are just missing). But
it'll do for now.</p>
<p><h2>Next steps</h2></p>
<p>I have designed an initial CAD model for the case I'd like to build:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3396"><img src="https://img.incoherency.co.uk/3396/thumb"></a></p>
<p>And ordered some fancy "Russian birch" plywood to make it out of.
Unfortunately I failed to notice when ordering that the plywood has a lead
time of about 25 days, so I won't be receiving that any time soon.</p>
<p>I still need to build a clock circuit. I have a bit of a mental
<a href="https://www.lesswrong.com/posts/EFQ3F6kmt4WHXRqik/ugh-fields">ugh field</a>
around this. I'm not sure why. I think there is a bit of a dependency loop,
because I don't know how to best design the clock circuit before I know
what frequency it needs to run at, and I won't know what frequency the
CPU can cope with until I have a better clock.</p>
<p>I would like to do some profiling of the compiler, assembler, and compiler
driver, to work out why it is taking nearly 60 seconds to compile a
1-line program. I'm sure a lot of it is overhead that will scale sub-linearly
with program size, but it definitely feels like this should be faster.</p>
<p>I have found that the VGA serial terminal does not seem to handle the
page up/down keys, at all. It's not just that my text editor doesn't
understand the escape sequences: it doesn't receive any escape sequences!
If I can't work out how to get the VGA serial terminal to send them, then
I'll probably just provide Ctrl-U and Ctrl-D as synonyms for page up/down.</p>
<p>I have also found that the VGA serial terminal sends code 127 for the "DEL"
key, whereas gnome-terminal (or Linux, or something else in the pipeline)
sends 127 for the backspace key. That's
annoying. Before discovering that, I had just supported every observed
variation of codes for each special key, so that it supports both types
of terminal transparently. Unfortunately I am now in some danger of
reinventing termcap, which I would like to avoid.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/scamp-20210624.html</link>
   <guid>http://incoherency.co.uk/blog/stories/scamp-20210624.html</guid>
   <pubDate>Thu, 24 Jun 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>SCAMP works at 1 MHz</title>
   <description><![CDATA[Thanks to Rory's suggestion of
CD4504 TTL-to-CMOS level shifters,
last night I finally succeeded in moving the CompactFlash glue logic out of the Arduino
and into physical hardware.]]></description>
   <content:encoded><![CDATA[<p>Thanks to <a href="http://www.thelifeadventuristic.co.uk/">Rory</a>'s suggestion of
<a href="https://www.ti.com/product/CD4504B">CD4504</a> TTL-to-CMOS level shifters,
last night I finally succeeded in moving the CompactFlash glue logic out of the Arduino
and into physical hardware.</p>
<p>Since I no longer need the Arduino code to sync anything to the clock signal, I'm
free to use the CTC to generate it, which can give a much higher frequency. I used
<a href="https://www.arduino.cc/reference/en/libraries/timerone/">TimerOne</a> to
generate a 1 MHz square wave (which is the maximum as far as I can tell), and the SCAMP hardware still appears to function correctly,
which is great news.</p>
<p>Here's a recording of a session running on the real hardware (it's 6 minutes long
so maybe you don't want to watch it all):</p>
<p><script id="asciicast-ighlDDjXyNnlVFtUM3lehChOv" src="https://asciinema.org/a/ighlDDjXyNnlVFtUM3lehChOv.js" async data-cols="80" data-rows="25"></script></p>
<p><h2>Performance</h2></p>
<p>I know it seems quite slow, but consider that <a href="https://incoherency.co.uk/blog/stories/scamp-compactflash.html">previously</a>
it took about 30 minutes just to boot up to the shell, and now it's <i>almost</i> usable interactively.
Things are moving in the right direction.</p>
<p>There is potentially scope to clock it even higher,
and there are definitely software improvements to be made. For example the kernel's CompactFlash reading/writing code
is all written in <a href="https://incoherency.co.uk/blog/stories/slang.html">SLANG</a> at the moment, which produces extremely unoptimised
code. Eventually I'll rewrite the inner loops in assembly language.</p>
<p><h2>Obvious problems</h2></p>
<p>The first obvious problem is the garbled text at the start. This is text output from the bootloader and
kernel, and the reason it is garbled is because the CPU is now running fast enough that it tries to
stuff characters into the UART faster than they can be transmitted! I didn't expect to run into this
problem so early, but it should be straightforward to fix, either by adding a bunch of <tt>slownop</tt> in
the worst case, or preferably by polling the UART status.</p>
<p>The second problem is that the space bar doesn't seem to work properly. I can not explain this. I didn't
observe any flipped bits in any other keypresses, so it is hard for me to imagine what is going on. Sometimes
pressing the space bar puts nothing on the screen, but invisibly terminates your input command line.
It acts as if the space bar sometimes inserts a <tt>0x00</tt> instead of <tt>0x20</tt>. Not sure what's
happening, but I look forward to debugging it.</p>
<p><h2>Next steps</h2></p>
<p>The immediate next step is to turn this mess of wires into a PCB:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3369"><img src="https://img.incoherency.co.uk/3369/thumb"></a></p>
<p>I'm very pleased to be at the point where the UART and the CompactFlash card are both working correctly.
I have found interfacing with the peripherals to be the most complicated part of building the computer,
because they are rather inscrutable black boxes that are hard to faithfully recreate in the emulator.</p>
<p>I think I might provide for 2 CompactFlash cards on the PCB. One would be purely internal and hold
the kernel and root filesystem, and the other
would be removable through the front panel, as a convenient way to transfer files
between the SCAMP and a modern computer. The kernel doesn't yet support more than 1 block device, and I'm
not exactly sure how I would support it. It might be simpler to have a "userspace" program responsible
for interacting with the removable device, rather than mounting it on the filesystem.</p>
<p>It's probably about time that I looked at building a proper clock circuit. I'm curious to know how fast
it can be clocked before it gets unstable.</p>
<p>And I still need to work on the wooden case that I keep talking about, fit a proper power supply inside it,
and make a PCB for the clock, and the power & reset switches.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/scamp-1mhz.html</link>
   <guid>http://incoherency.co.uk/blog/stories/scamp-1mhz.html</guid>
   <pubDate>Sat, 29 May 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>A short pendulum with a long period</title>
   <description><![CDATA[The period of a pendulum is proportional to the square root of its length: to double the period,
the pendulum needs to become 4x as long. But actually physics has no idea how long your pendulum is,
the thing that really matters is the radius of the arc that the centre of mass travels
through. There's no inherent reason that we wouldn't be able to increase the radius of this arc
without increasing the height of the pendulum.]]></description>
   <content:encoded><![CDATA[<p>The period of a pendulum is proportional to the square root of its length: to double the period,
the pendulum needs to become 4x as long. But actually physics has no idea how long your pendulum is,
the thing that <i>really</i> matters is the radius of the arc that the centre of mass travels
through. There's no inherent reason that we wouldn't be able to increase the radius of this arc
without increasing the height of the pendulum.</p>
<p><h2>Demo</h2></p>
<p>Here's a quick-and-dirty <a href="https://brm.io/matter-js">Matter.js</a> demo of the simplest mechanism I could think of:</p>
<p><canvas style="max-width:100vw; max-height:500px" id="long-pendulum-display"></canvas></p>
<p>If it runs out of energy you can refresh the page or give it a kick with your
mouse.</p>
<p>The pendulum on the left is a "normal" pendulum. The one on the right
has a linkage that makes the effective pivot point of the pendulum swing
left and right with the weight. This has the effect of flattening out the
path of the weight, which approximates an arc of greater radius.</p>
<p>I had to "cheat" in the demo because I couldn't work out how to use Matter.js
constraints to keep the angles of the short and long arm synchronised. The
pivot at the top is actually static as far as Matter.js is concerned, and
my code manually updates its position. This is why the green line has
some slight deviations.</p>
<p><h2>How it could work in real life</h2></p>
<p>I wasn't clever enough to include a representation of the actual linkage
in the animation, but
I envisage something like this, where there is a sprocket at
each end of the short arm, with a chain that keeps the angles synchronised:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3355"><img src="https://img.incoherency.co.uk/3355/thumb"></a></p>
<p>The sprocket at "pivot 1" is fixed to the frame of the apparatus, and the
sprocket at "pivot 2" is fixed to the long arm, so that as the long arm
rotates, "pivot 2" pulls itself around the chain, which rotates the short
arm around "pivot 1" because the sprocket at "pivot 1" can't move.</p>
<p>If you spend some time thinking about it you might undertand it. Instead
of a chain and sprockets we could just as easily have a gear train with
an odd number of gears, or a pair of pulleys with a string fixed at
opposite sides, or possibly something even better.</p>
<p><h2>Why it's good</h2></p>
<p>I have a vague idea that I'd like to build a mechanical clock at some
point. I'm kind of thinking a floor-standing clock of grandfather clock
scale, but with less fine woodworking, and more exposed workings of
unusual design.</p>
<p>I think it would be fun if the clock ticked really slowly and purposefully,
with the second hand jumping several seconds with every tick. To
achieve this with a standard pendulum, the clock would need to be very
tall indeed. If the clock ticks twice per period of the pendulum (once
for each direction), then to get a tick every 5 seconds you would need a
10-second period, which implies a pendulum that is 25 metres tall,
which is clearly absurd.</p>
<p><h2>Why it's bad</h2></p>
<p>It is probably very difficult to build the two-armed-linkage with
sufficiently-low friction that it would actually work in a clock. I don't know how
much energy an escapement can typically impart into a pendulum with
each tick, but it is presumably low, otherwise it would compromise the
pendulum's regularity (maybe?).</p>
<p>More importantly, the fact that the two-armed-linkage pendulum does not
swing through a true circular path means that its period is not truly
constant. The mean radius decreases as the weight swings higher, which presumably means
the period decreases as the weight swings higher. To get a constant period
out of this pendulum, you'd need to ensure that it swings to the same
height on every stroke, and if you can do that then you don't need a
pendulum in the first place.</p>
<p>My thinking is that the period won't vary <i>too</i> much throughout the
useful range of the pendulum, and it doesn't matter if the clock drifts
a bit anyway. It would be good to do some calculations to quantify how the
period changes with the swinging height. But I can't immediately see
how to do that.</p>
<p><h2>Parameters</h2></p>
<p>A normal ideal (spherical cow, frictionless vacuum, etc.) pendulum only has
1 parameter: the length. Or, more precisely, the radius of the arc that
the centre of mass swings through.</p>
<p>Our two-armed-linkage pendulum has <i>three</i> interesting parameters:
the length of the long arm, the ratio of the length of the short
arm to the long arm, and the gear ratio of the sprockets.</p>
<p>As the short arm length tends towards 0,
the motion of the two-armed-linkage pendulum tends towards that of the
classical pendulum. As the short arm length tends towards that of the
long arm, the "arc"
tends towards a straight line, where gravity will no longer have
any effect on the weight. Where the "short arm" is longer than the
"long arm", I think the arc is inverted and
gravity will pull the weight towards whichever side it is already on,
rather than always pulling towards the centre.</p>
<p>It's not immediately clear to me what happens as the gear ratio changes.
My demo and sketch assume a 1:1 ratio, but it is possible that there is a
better choice which would more faithfully approximate a circular arc.</p>
<p><script src="js/matter.js"></script>
<script src="js/long-pendulum.js"></script>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/long-pendulum.html</link>
   <guid>http://incoherency.co.uk/blog/stories/long-pendulum.html</guid>
   <pubDate>Sat, 08 May 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>A method and apparatus for polishing shafts</title>
   <description><![CDATA[I have invented a new tool. From time to time, I expect you, like me, need to sand down the outside of a piece of round
bar. I expect you, like me, chuck the round bar in a drill or a lathe, spin it up, and then hold sandpaper
against it to sand it. This works fine when you are able to spin the round bar, but sometimes the bar is
already connected to something big or inconvenient and you are not able to spin it, and you are left wondering
what to do.]]></description>
   <content:encoded><![CDATA[<p>I have invented a new tool. From time to time, I expect you, like me, need to sand down the outside of a piece of round
bar. I expect you, like me, chuck the round bar in a drill or a lathe, spin it up, and then hold sandpaper
against it to sand it. This works fine when you are able to spin the round bar, but sometimes the bar is
already connected to something big or inconvenient and you are not able to spin it, and you are left wondering
what to do.</p>
<p>Well wonder no longer!</p>
<p><a class="img" href="https://img.incoherency.co.uk/3335"><img src="https://img.incoherency.co.uk/3335/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3346"><img src="https://img.incoherency.co.uk/3346/thumb"></a><br>
<small>(not pictured: there are springs on the sandpaper "fingers" so that they apply force inwards)</small></p>
<p>Simply chuck up the little shaft to your cordless drill, stick the bar you need to sand through the large hole,
then spin up the drill and the little pieces of sandpaper will polish your bar.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3347"><img src="https://img.incoherency.co.uk/3347/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3349"><img src="https://img.incoherency.co.uk/3349/thumb"></a></p>
<p><h2>Drawbacks</h2></p>
<p>Currently this is just a proof-of-concept and there are some clear drawbacks with the design:</p>
<p><ul>
<li>the casing is enormous compared to the size of bar you can sand</li>
<li>the springs that press on the sandpaper are too weak</li>
<li>the pieces of sandpaper are too small</li>
<li>it is difficult and inconvenient to load the bar because you have to hold all 3 fingers out of the way simultaneously</li>
<li>the gear ratio is too extreme, so the sandpaper turns too slowly</li>
<li>making the small shaft and pinning it to the small gear is time-consuming, I should just have a hex hole in the gear driven by an allen key tool in the drill, or similar</li>
</ul></p>
<p>But I think the concept is proven, and if I can be bothered I might design a better version and print it in a better
material than the PLA used here. I've been making mechanical parts with
<a href="https://prusament.com/materials/prusament-pc-blend/">Prusament PC Blend</a> recently,
which was released without much fanfare and I haven't seen very many people talking about, but which I think is a brilliant
material. It appears to be much stronger than PETG and hardly any more difficult to print with. Surprisingly, it is slightly
more flexible than PLA, even though I recall <a href="https://eu.polymaker.com/product/polymax-pc/">PolyMax PC</a> to be
a bit stiffer than PLA. I guess the "Blend" is doing a lot of work.</p>
<p>I would turn the little circular pads of sandpaper into long thin rectangles. Only the centre part of the circle ever touches the
bar, because the surface is flat and the bar is curved, so making them "wider" serves no purpose, but making them "longer" means
they contact more of the bar.</p>
<p>I would switch to probably a 1:1 gear ratio. I don't really know why I didn't do that the first time.</p>
<p>The size of the large hole is limited by the size of large-bore thin-walled bearing that is easy to acquire. I've used
"6708" bearings, which have a 40mm bore. It is rare for me to work with round bar any larger than this, so I'm not worried
for now. If I wanted to go any larger I would probably ditch the large-bore bearing and resort to 3 smaller bearings placed around
the outside, roughly like the base on my <a href="https://incoherency.co.uk/blog/stories/pikon-telescope-hardware.html">telescope mount</a>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1961"><img src="https://img.incoherency.co.uk/1961/thumb"></a></p>
<p>I wonder if there would be some way to have the springs push the sandpaper fingers from an angle instead of radially. That
might reduce the required diameter of the large gear:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3354"><img src="https://img.incoherency.co.uk/3354/thumb"></a></p>
<p>You'd probably need to have a "half-cylinder" of sandpaper instead of a flat rectangle, because the angle will change with the
radius. Maybe it's not an improvement.</p>
<p><h2>Inspiration</h2></p>
<p>The tool is 50% <a href="https://www.youtube.com/watch?v=cLQnDCRjXhg">the "drill-powered through-wrench"</a> which
is basically a way to use a drill to turn a nut on a threaded rod that is longer than a deep socket:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3350"><img src="https://img.incoherency.co.uk/3350/thumb"></a></p>
<p>And 50% those inside-bore honing tools:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3351"><img src="https://img.incoherency.co.uk/3351/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3352"><img src="https://img.incoherency.co.uk/3352/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/polishing-shafts.html</link>
   <guid>http://incoherency.co.uk/blog/stories/polishing-shafts.html</guid>
   <pubDate>Sat, 01 May 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>SCAMP has booted up to the shell for the first time</title>
   <description><![CDATA[I reached another good milestone on SCAMP this week: the physical hardware booted all the way up to the shell.
Granted, it only happened once, and I couldn't type any input once it got there. But it suggests that there are
no fundamental problems with the hardware design that will prevent the computer from working, which I am very happy about.]]></description>
   <content:encoded><![CDATA[<p>I reached another good milestone on SCAMP this week: the physical hardware booted all the way up to the shell.
Granted, it only happened once, and I couldn't type any input once it got there. But it suggests that there are
no fundamental problems with the hardware design that will prevent the computer from working, which I am very happy about.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3328"><img src="https://img.incoherency.co.uk/3328/thumb"></a></p>
<p>I'm currently "interacting" with the computer using an FTDI cable (basically a USB serial port). I'm still planning
to eventually acquire some sort of hardware terminal, either a ready-made product or something I'll put together based around
Marco Maccaferri's <a href="https://www.tindie.com/products/maccasoft/vga-serial-terminal-kit-for-rc2014/">RC2014 VGA Serial Terminal Kit</a>,
which I use and like on my RC2014.</p>
<p><h2>SCAMP boot process</h2></p>
<p>The SCAMP boot process has 3 stages. There's the boot ROM, the kernel, and <tt>init</tt>. The boot ROM loads
the kernel off the disk, the kernel stays in memory to provide system call implementations and loads <tt>init</tt>,
and <tt>init</tt> (currently) just prints the message of the day and executes the shell, at which point the user is in control.</p>
<p>As measured in the emulator, it takes about 36 million clock cycles to go from zero to the shell, but this can
be improved a lot. 60% of the time is spent reading/writing the disk. These functions are prime candidates
for optimisation in assembly language. Also, <tt>init</tt> shells out to <tt>cat</tt> to print the
message of the day, which is really an unacceptable performance cost at slower clock speeds. It would be better
to have <tt>init</tt> read <tt>/etc/motd</tt> itself.</p>
<p><h3>Boot ROM</h3></p>
<p>The boot ROM is stored on 2 EEPROMs (all SCAMP memory is based on 16-bit words, so there's one EEPROM for the least-significant byte,
and one for the most-significant byte) which are permanently mapped at addresses 0 to 255.</p>
<p>The memory card decides whether any given memory access should go to ROM or RAM based on checking the 8 most-significant bits: if
any are 1 then it's RAM, otherwise it's ROM. This is accomplished with a pair of 74LS32 OR chips, and a 74LS00 NAND chip:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3327"><img src="https://img.incoherency.co.uk/3327/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3325"><img src="https://img.incoherency.co.uk/3325/thumb"></a></p>
<p>The first three 16-bit words from the disk are:</p>
<p><ol>
<li>magic number to verify that the disk contains a SCAMP kernel (0x5343)</li>
<li>start address of kernel in memory</li>
<li>length of kernel</li>
</ol></p>
<p>The <a href="https://github.com/jes/scamp-cpu/blob/master/bootrom.s">boot ROM</a> loads the first 3 values, checks that they look
sensible, and then continues reading the requisite number of words until the entire kernel is loaded into memory at the requisite
address, and finally jumps to that address to start executing the kernel.</p>
<p>Currently every single one of the 256 available words in ROM are used, and the diagnostic messages are still a bit terser than I would prefer,
but it fits, which is all that matters.</p>
<p><h3>Kernel</h3></p>
<p>The kernel has very little to do at boot time. It initialises the serial device (which is probably unnecessary since the boot ROM
already did that), finds an unused block on the filesystem (for boring reasons), and executes <tt>/bin/init</tt>.</p>
<p><h3>init</h3></p>
<p><tt>init</tt> has even less to do than the kernel:</p>
<p><pre><code>system(["/bin/cat", "/etc/motd"]);
chdir("/home");
while (1)
    system(["/bin/sh"]);</code></pre></p>
<p>But it takes a long time because <tt>system()</tt> in SCAMP/os is basically a practical joke taken too far: it swaps the running process out to
disk, loads the child process, runs it, and then swaps the parent process back in and resumes where it left off.</p>
<p><h2>CompactFlash interface</h2></p>
<p>I chose to use CompactFlash instead of an SD card because the parallel access is much more convenient and performant than SPI. I'm using the
CompactFlash card in "True IDE" mode, which also leaves the door open for potentially replacing it with a real hard disk at some point
with minimal software changes. Happily, True IDE mode supports 16-bit transfers natively, so I don't even have to worry about combining
2 bytes into a word or splitting a word into 2 bytes. Unhappily, it seems to be little-endian, so the filesystem is kind of interlaced
when viewed bytewise. It's tempting to swap the upper and lower byte by plugging them into the bus "backwards", but I think this might
just create more confusion than it solves.</p>
<p>I bought a CompactFlash breakout board on eBay to get this working on a breadboard, and I may even use the breakout board on the final PCB
because it seems a lot more convenient than soldering the CompactFlash connector myself.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3329"><img src="https://img.incoherency.co.uk/3329/thumb"></a></p>
<p>I learnt how to speak to the card by reading a couple of PDFs that I found online:</p>
<p><ul>
<li><a href="https://github.com/jes/scamp-cpu/blob/master/pdf/ti-compact-flash-spra803.pdf">CompactFlash Memory Card Interface to the TMS320VC54x</a> from Texas Instruments</li>
<li><a href="https://github.com/jes/scamp-cpu/blob/master/pdf/sandisk-compactflash.pdf">SanDisk CompactFlash Memory Card OEM Product Manual</a> from SanDisk</li>
</ul></p>
<p>But the set of information that you need to know is <i>much</i> smaller than either of those PDFs, so I intend to write some more beginner-focused
documentation.</p>
<p><a href="https://www.grahamedgecombe.com/">Graham</a> told me that if your computer has a long bus (like mine does, and like the
RC2014 does), then you may find that newer CompactFlash cards
don't quite work correctly. I found that mine would sometimes drop certain values. Usually the same ones, but not in any pattern that was
obvious to me. There are some details of the problem in PickledDog's <a href="https://github.com/PickledDog/rc-cfcard">rc-cfcard</a> README:</p>
<p><blockquote>the fast level transitions of modern CompactFlash are only intended for the short traces between card and interface in a system, and do not play nice with the long paths of the unterminated RC2014 bus</blockquote></p>
<p>I'm not a high enough wizard to know what this actually means, or why it causes the behaviour I observed. But I took a punt on a much older
CompactFlash card (you can identify the older ones by their lower storage capacity), and that one worked straight away, so there
might be something in it.</p>
<p>Connecting the CompactFlash card to the SCAMP bus is mostly just a case of connecting up the wires in the right order, but a
small amount of glue logic is required:</p>
<p><ul>
<li><tt>IORD- = !DO</tt></li>
<li><tt>IOWR- = !WR</tt></li>
<li><tt>CS0- = A3 nand A8</tt></li>
</ul></p>
<p><tt>DO</tt> goes high when the CPU wants a peripheral to output something, but the CompactFlash card wants an active-low signal, so we just invert it.</p>
<p><tt>WR</tt> is generated by the UART card, based on <tt>DI</tt> (CPU wants a peripheral to input something) and the clock signal. We take this signal
from the UART card and invert it for the CompactFlash card.</p>
<p><tt>CS0-</tt> needs to go low when we want to select the CompactFlash card. I have dedicated the <tt>A8</tt> bit of the address register to selecting
CompactFlash, and conditional on <tt>A8</tt>, <tt>A3</tt> selects the first card. (I'm not sure if there will ever be more than 1, but it doesn't
hurt anything to provide for more now).</p>
<p>I was initially implementing this logic on the Arduino Uno that also generates the clock signal, and at this point the system booted up, which I liked.
It took about half an hour to completely boot though, because the clock signal was only about 20 kHz.</p>
<p>Obviously I need to move the glue logic out of the Arduino and onto physical chips
in order to make the real CompactFlash interface. All 3 of those operations can be provided by a single 74xx00 NAND chip, so that's what I tried.</p>
<p>Unfortunately it didn't work. I think the problem is that CompactFlash is based on CMOS logic, which is quite strict about having a good 5v for a logic
1, whereas TTL is allowed to output anything above 2.7v for a logic 1. I tried a 74LS00 and 74HCT00 but it didn't work with either of them. I have
ordered a 74HC00, but I think this might have the same problem from the opposite direction: it will generate nice clean CMOS outputs, but will
also require nice clean CMOS inputs. So if that doesn't work then I may try to generate these signals using bare transistors, and if even
<i>that</i> doesn't work then I'll need to go away and learn harder.</p>
<p><h2>Next steps</h2></p>
<p>After I've got the CompactFlash card working with the glue logic in hardware instead of Arduino code, I will need to debug why input
wasn't working when I got to the shell. I think it is supposed to work, and it works in the emulator which very-slightly emulates the
physical UART, so I'm not sure what I missed. Hopefully it shouldn't be difficult.</p>
<p>Once the CompactFlash card and keyboard input are working, we're pretty much home free, because that's where the dark magic ends. The rest is
just building the wooden case that I keep getting distracted from, connecting up the real power supply, making a real clock source, and
fleshing out the system software and libraries in preparation for Advent of Code.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/scamp-compactflash.html</link>
   <guid>http://incoherency.co.uk/blog/stories/scamp-compactflash.html</guid>
   <pubDate>Sun, 25 Apr 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The kilo editor</title>
   <description><![CDATA[Thanks to the excellent Build Your Own Text Editor tutorial,
SCAMP/os now has an editor. It's pretty bare-bones, but perfect for what I need.]]></description>
   <content:encoded><![CDATA[<p>Thanks to the excellent <a href="https://viewsourcecode.org/snaptoken/kilo/">Build Your Own Text Editor</a> tutorial,
<b>SCAMP/os</b> now has an editor. It's pretty bare-bones, but perfect for what I need.</p>
<p>The tutorial walks you through implementing the <a href="http://antirez.com/news/108">kilo</a> editor, so-named because it's less than
1000 lines of C.
Ported to <a href="https://incoherency.co.uk/blog/stories/slang.html">SLANG</a> (and with syntax highlighting not supported), it currently totals 811 lines.
I skipped the syntax highlighting partly because of
performance considerations (SCAMP is a pretty slow CPU), but mostly because I felt that colours would ruin the aesthetic.</p>
<p>Here's a demo of the editor:</p>
<p><script id="asciicast-404770" src="https://asciinema.org/a/404770.js" async></script></p>
<p>And here's the source of my version: <a href="https://github.com/jes/scamp-cpu/blob/master/sys/kilo.sl">https://github.com/jes/scamp-cpu/blob/master/sys/kilo.sl</a>.</p>
<p>Using kilo is basically like using nano but with a lot fewer features.</p>
<p><h2>Implementation details</h2></p>
<p>Kilo stores each line as a C string on the heap (<tt>realloc()</tt>'d as needed), with another
dynamically-resizing array storing a pointer to each line. This is good because it is easy, but it does mean
there is sometimes a large block copy when a string/array needs to be moved. It seems fine enough in practice though, even on (emulated) SCAMP.</p>
<p>The "real" kilo actually stores 2 copies of each line: one is the contents of the line as they appear in the file, and the other is
as they appear on the screen. The principle difference is that tab characters in the file are rendered as a series of spaces on the
screen. You might be tempted to skip this, but it results in weird behaviour when the screen scrolls horizontally. Perhaps you could
work around that by snapping the horizontal scroll to the tab stops? Maybe that is worth trying.</p>
<p>To save on memory usage, SCAMP kilo only stores 1 copy of each line and generates the display version only when needed. You
might think this is a premature optimisation, but consider that the source for the compiler is 27K characters. Even with no extra overhead in kilo,
storing 2 copies of that would be 54K, and with the kernel taking up 14K, we've already ran out of address space. (As it happens, kilo
currently can't open the compiler source <i>anyway</i>, because other inefficiencies push the total over 64K - I eventually want to fix this).</p>
<p>The real kilo redraws the screen after every keypress, which is totally fine on modern computers but is definitely not going to fly on
SCAMP: e.g. it would take more than 2 seconds to do a full screen redraw at 9600 baud. For the SCAMP version I keep track of which lines have changed
since they were last drawn, and only redraw those that have changed.</p>
<p><h2>Compared to ZDE 1.6</h2></p>
<p>On the <a href="https://incoherency.co.uk/blog/tags/rc2014.html">RC2014</a> I use
the <a href="https://techtinkering.com/2008/10/21/installing-zde-1-6-a-programmers-editor-for-cpm/">ZDE 1.6</a> editor. It is more feature-complete
than kilo, but quite weird, and not well-suited to modern keyboards. The backspace key does what the delete key should do, and to get a backspace you need
to type Ctrl-H. Sometimes it writes <tt>^I</tt> at the end of a line for no apparent reason (I don't think it's anything to do with tab characters).
The key shortcuts are confusing and hard to learn, because they don't match <i>any</i> other software I've ever used.</p>
<p>While kilo is clearly inferior to ZDE in terms of <i>features</i>, it is much easier to use, mainly because the lack of available operations means
typing the wrong keys is unlikely to make it run off in a direction you didn't want.</p>
<p>To my untrained fingers,
ZDE sometimes feels a bit like trying to use vi with caps lock stuck on.
Or like trying to drive a car but the steering wheel operates the throttle, the gear lever operates the brakes, and you steer by winding the windows
up and down. It's mostly fine as long as you go slowly and carefully, but if you slip into your usual flow it all comes crashing down.</p>
<p>OK, that's a bit unfair. ZDE is definitely the easiest editor I've found for CP/M. Maybe I should port kilo to CP/M.</p>
<p><h2>Hardware</h2></p>
<p>Apart from working on the editor, I've made a bit more progress on the hardware. I have now got a UART wired up on a breadboard, and communication
is working in both directions:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3303"><img src="https://img.incoherency.co.uk/3303/thumb"></a></p>
<p>From left to right, we have a 1.8432 MHz quartz crystal and a resistor and a couple of capacitors, forming the oscillator from which the baud rate
clock is derived. Then there's the UART itself, this is a <a href="https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter#UART_models">16450</a>, which is equivalent to an 8250 but with support for higher baud rates. Then the little black button is the reset button, and finally there's an Arduino Nano.</p>
<p>The Arduino is there to:</p>
<p><ul>
<li>generate a square wave for the clock signal</li>
<li>invert the reset signal for the UART (the UART has active-high reset whereas the SCAMP has active-low)</li>
<li>create the "WR" pulse to tell the UART we're writing to it</li>
</ul></p>
<p>The fastest I can bit-bang a square wave from C on the Arduino is about 80 kHz, and SCAMP still seems to work correctly at this speed, which is a good
sign. I'll be disappointed if I can't get another factor of 10 on that, and delighted if I can get another <i>two</i> factors of 10.</p>
<p>I'm still umming and ahhing about how I'm going to generate the "WR" pulse without the Arduino.</p>
<p>"WR" is an input to the UART that tells it we want to write to it.
The problem is that the UART does not have a clock input,
and it seems to take input from the bus at the falling edge of "WR". The closest signal to "WR" that SCAMP generates is "DI" which says we want an
IO device to take input at the rising clock edge. Simply connecting "DI" to "WR" doesn't work because "DI" doesn't have a falling edge until the
next clock cycle starts. At the start of the next cycle, "DI" and the data on the bus both disappear at the same time, which leads to the UART sometimes (most of the
time) not reading the correct input. We need a way to make the "WR" signal have a falling edge when the clock edge rises, rather than when "DI" falls.</p>
<p>I think this shows what I mean:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3304"><img src="https://img.incoherency.co.uk/3304/thumb"></a><br>
<small>(drawn with <a href="https://wavedrom.com/tutorial.html">WaveDrom</a>)</small></p>
<p>I want to generate a signal that looks like "WR (wanted)". A potential solution would be to create "DI & !CLK", but it has the risk of a small glitch
at the next falling clock edge while "DI" is still high. Past that, I'm not sure. Maybe I have to come up with something based around some
flip-flops? I think it would be fine to pulse "WR" when given a rising edge of the clock, rather than holding it high while the clock is low. Maybe that
would be easier. Something like the 74121-based single-stepping circuit in my <a href="https://incoherency.co.uk/blog/stories/rc2014-frontpanel.html">RC2014 front panel</a>.</p>
<p>I have found working on the electronics quite difficult. On several occasions I have reached a working configuration, made a small change,
determined that it did not work, reverted the change, and found that the formerly-working configuration no longer worked, with no way to know whether
I have permanently broken something, failed to properly restore the previous configuration, or the previous configuration only worked by accident for
some unrelated reason. Electronics really needs better development tooling.</p>
<p>I have splashed out on a DSO (I went for a "Hanmatek DOS1102", which is cheap-ish but well-reviewed and seems fine). Unfortunately I haven't found it to be a great deal
of use. For example, if I connect it to the clock signal, the CPU stops working and I have no idea why. The clock signal still looks fine to me:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3300"><img src="https://img.incoherency.co.uk/3300/thumb"></a></p>
<p>But evidently the magic pixies know they're being observed and they don't like it.
It seems like you can't ever use a DSO to debug anything because the mere presence of the DSO changes the behaviour of the system you're connecting it
to. In hardware, every bug is a <a href="https://en.wikipedia.org/wiki/Heisenbug">heisenbug</a>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/kilo.html</link>
   <guid>http://incoherency.co.uk/blog/stories/kilo.html</guid>
   <pubDate>Sat, 03 Apr 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>SCAMP is alive</title>
   <description><![CDATA[I have reached a good milestone on the SCAMP hardware: it can now execute code! It runs all the way through the
test program
correctly.]]></description>
   <content:encoded><![CDATA[<p>I have reached a good milestone on the SCAMP hardware: it can now execute code! It runs all the way through the
<a href="https://github.com/jes/scamp-cpu/blob/8fb0ce4f0564ace6b52dd6563f624750b51debd3/testrom.s">test program</a>
correctly.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3291"><img src="https://img.incoherency.co.uk/3291/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3296"><img src="https://img.incoherency.co.uk/3296/thumb"></a></p>
<p>The card cage helps to hold the cards in place, and to avoid bending the pins when unplugging them.
I also anticipate that it will simplify the construction of the case, because the case won't need to hold the rails.
Unplugging the ALU is still pretty hard, because it is plugged into 120 pins.</p>
<p>I still haven't made a clock, so for now the CPU is being clocked by a short Arduino program. I've gone up as high as 10 Hz
without observing any instability. I don't yet have any way to infer the state of the machine without looking
at the LEDs, so if it went any faster than that I wouldn't even know whether it was working or not. Next steps
are to make an adjustable 555 timer-based clock, and interface with the <a href="https://en.wikipedia.org/wiki/8250_UART">8250
UART</a>.</p>
<p>The test program just outputs the numbers 0 to 24 to the device at address 0. Each number is generated differently,
and tests different things, starting off by just sticking the number in the <tt>x</tt> register and outputting that,
followed by addition, subtraction, bitwise shift, bitwise logic, stack manipulation, unconditional jump, conditional jump,
looping, relative jump, and function calls.</p>
<p>There is no actual device at address 0, so correct operation is verified by watching the lights. To output a value to device 0:</p>
<p><ul>
<li>the address register contains 0</li>
<li>the bus contains the value</li>
<li>the <tt>DI</tt> signal comes on, to tell the device to take input</li>
</ul></p>
<p>Here's a video of SCAMP running the test program. If you pause the video every time <tt>DI</tt> comes on, you might be able
to convince yourself that it is outputting the correct values:</p>
<p><p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/1WwF2P9zLtY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p></p>
<p>(The button I have my finger on at the start is the "reset" button).</p>
<p>And here's a look at the wiring of the LEDs on the instruction card:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3289"><img src="https://img.incoherency.co.uk/3289/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3290"><img src="https://img.incoherency.co.uk/3290/thumb"></a></p>
<p><h2>Bugs</h2></p>
<p>Although I had already checked that everything would work at least 3 different ways (Verilog simulation, running on an FPGA,
and the <a href="https://github.com/jes/scamp-cpu/blob/master/emulator/scamp.c">SCAMP emulator in C</a>), there were
still a lot of fun bugs to find and fix after I put the PCBs together.</p>
<p><h3>Inverted "enable" pins on decoders</h3></p>
<p>Two <a href="https://github.com/jes/scamp-cpu/blob/master/pdf/74138.pdf">74LS138</a> "3-to-8" decoders are used, each one decodes 3 bits of the microinstruction word into a selection of 8 possible
input or output components for the bus.</p>
<p>(This design does mean it's not possible to output to 2 components
simultaneously, but that's not something I want to do very often, and saving space in the microinstruction
word was more important to me).</p>
<p>The 74xx138 has 3 "enable" pins. For it to apply an output, all 3 must be enabled. I had failed to notice that 2 of these
enable inputs are active-low instead of active-high:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3283"><img src="https://img.incoherency.co.uk/3283/thumb"></a></p>
<p>The "E1" and "E2" (pin 4 and 5) inputs have little circles to indicate that the signal is inverted, but I had connected these
pins to VCC instead of GND, which means the decoders were never enabled. D'oh! My solution was to pop
pins 4 and 5 out of the socket and solder a little wire to GND, and this worked.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3292"><img src="https://img.incoherency.co.uk/3292/thumb"></a></p>
<p><h3>bus_in conditional on not using the ALU</h3></p>
<p>The "bus_out" decoding is slightly more complicated than "bus_in". One of the components that can output to the bus is the ALU,
but the ALU also needs 6 more control signals to select its operation, which are all inapplicable when the ALU is not in use.
For this reason, the bit that selects the ALU (<tt>EO</tt>) is separate from the "bus_out" bits, and the "bus_out" bits overlap with the ALU
function selection:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3284"><img src="https://img.incoherency.co.uk/3284/thumb"></a></p>
<p>(See under "Decoding" in <a href="https://github.com/jes/scamp-cpu/blob/master/doc/UCODE.md">doc/UCODE.md</a>).</p>
<p>This means that for the "bus_out" decoder, one of the enable inputs needs to come from <tt>EO</tt>. So far so good. But when I designed the
schematic, I copy and pasted the "bus_out" decoder to create the "bus_in" decoder, and forgot to remove the <tt>EO</tt> input from pin 6:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3285"><img src="https://img.incoherency.co.uk/3285/thumb"></a></p>
<p>This means the output of the ALU can never be consumed, because when the ALU is outputting to the bus, nothing is inputting.</p>
<p>My solution was to pop pin 6 out of the socket, and connect it to VCC with a little wire (also visible in the above pic), and this worked.</p>
<p><h3>IOLH inverted</h3></p>
<p><tt>IOL</tt> and <tt>IOH</tt> ask for the lower 8 bits of the instruction word to be placed on the bus, with the upper 8 bits set to either
0 (for <tt>IOL</tt>) or 1 (for <tt>IOH</tt>). All of these signals are active-low, because the enable pins on the buffers are active-low.</p>
<p>For some reason, I decided that I could create <tt>IOLH</tt> by NAND of <tt>IOL</tt> and <tt>IOH</tt> (because, by De Morgan's Law, NAND is just OR but
for active-low inputs), but obviously this gives an active-high output. I had a couple of spare NAND gates on the same chip, so
my solution was to pop the <tt>IOLH</tt> output pin out of the socket, feed it into the 2 inputs to another NAND gate (grey wire) to use it as an
inverter, and feed the output of that NAND gate into the <tt>IOLH</tt> pin in the socket (blue wire), and this worked.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3293"><img src="https://img.incoherency.co.uk/3293/thumb"></a></p>
<p>I must have been tired or distracted when I designed the instruction card, as it has been the source of almost all of the mistakes!</p>
<p><h3>Sequencer reset glitch</h3></p>
<p>So far, all of the mistakes have been simple logic errors, but the sequencer reset glitch was quite subtle, and I am pleased
to have figured out what the problem was.</p>
<p>The first 24 or so instructions in the test program were executing correctly, but the 25th was only executing 3 of its 4 microcode
steps. The problem was that the 3rd step used the ALU, and set the <tt>NY</tt> (negate Y) bit.</p>
<p>The sequencer counts up on every clock cycle. The upper 8 bits of the "micro-program
counter" come from the instruction opcode, and the lower 3 bits come from the sequencer. Not all instructions take 8 cycles,
so there is a signal <tt>RT</tt> (for "reset T-state") which is used to reset the sequencer to 0. This signal acts immediately, without
waiting for a clock edge, so as soon as <tt>RT</tt> goes high, the sequencer resets to 0 which resets the "micro-program counter" to 0
for that cycle.</p>
<p>Since the combination of <tt>RT</tt> with <i>any</i> other control signals is meaningless (<tt>RT</tt> happens immediately, which precludes anything else),
I thought it was quite wasteful to dedicate an entire bit of the microinstruction word to it. I encoded it in bit 11, which is shared with
an ALU control signal: if the ALU is in use, bit 11 sets <tt>NY</tt> for the ALU. If the ALU is not in use, bit 11 sets <tt>RT</tt>.</p>
<p>The problem is that in real-life, signals don't all change simultaneously. If bit 11 ("<tt>NY</tt> or <tt>RT</tt>") comes high even fractionally before bit 15 ("I don't want to use the ALU") goes low, then
we very briefly have a state where <tt>RT</tt> is set. This immediately resets the sequencer to 0, stopping the current instruction and
moving to the fetch cycle of the next instruction.</p>
<p>That was pretty hard to figure out, but the fix was easy. I have some unused bits in the microinstruction word (I was thinking they might
be useful for controlling something like a hardware stack pointer in the future), so I moved <tt>RT</tt> to one of the unused bits. Then I just
needed to pop the sequencer's reset pin out of its socket and connect it to the new signal from the microcode.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3294"><img src="https://img.incoherency.co.uk/3294/thumb"></a></p>
<p>I don't know why this problem didn't arise when running the CPU on the FPGA. Maybe I got lucky? Maybe there is some secret internal clocking going on
in the FPGA that prevents the problem?</p>
<p>I think if I hadn't managed to work out what was going on here,
I would have just disconnected the <tt>RT</tt> signal. The computer would work, just slower: every instruction would always take 8 clock cycles,
even when it could be done in 3.</p>
<p><h2>Next steps</h2></p>
<p>I think the next thing I want to do is get the UART working on the breadboard. I think it should be straightforward, other
than the fact that debugging anything without text output is inconvenient. At least getting the UART working will make everything
else easier to debug.</p>
<p>Once I have the UART working I'll be able to start
running the clock faster, and then I can think about building the "real" clock instead of using an Arduino. I think I'll want 4
clock sources selectable: manual clock with a switch, adjustable 555 clock with a potentiometer, fixed crystal oscillator, and an
external clock input. The clock card would also have the reset button and probably a power switch.</p>
<p>And then finally I'll want to implement some sort of storage. The emulator currently provides a made-up block device that provides 1
byte per input instruction, and I know that this is borderline on being too slow to be acceptable. This leads me to rule out the idea of bit-banging
SPI to an SD card, which leaves CompactFlash as the most likely storage medium. I'm not sure how much trouble I'll have interfacing
with a CompactFlash card, I haven't found documentation to be particularly easy to find or understand. There are really only 2 primitives I need,
though: read a 512-byte block and write a 512-byte block. Once I can handle those 2 primitives, we're done. I should then be able to
stick my operating system on a CompactFlash card and boot it up for real!</p>
<p><h2>Software</h2></p>
<p>I've also made some progress on the software. Arguably more than on the hardware, but software is easier
for me, so it doesn't feel like as much.</p>
<p>The system is usable but relatively slow, even with the emulator running about 20x faster than I expect the real hardware will. Mostly this is down
to a combination of the slow block device interface, slow stack and bit-shift operations, bad code generation by my compiler, and code
written by me without appropriate regard for how slow the CPU is.</p>
<p>But it <i>works</i>, which is good. A lot of the simpler Unix utilities are there (in a primitive form, at least): <tt>cat</tt>, <tt>echo</tt>, <tt>grep</tt>, <tt>head</tt>,
<tt>ls</tt>, <tt>mkdir</tt>, <tt>more</tt>, <tt>mv</tt>, <tt>pwd</tt>, <tt>rm</tt>, <tt>stat</tt>, <tt>wc</tt>. There's an
interactive shell with support for IO redirection and globs. It doesn't yet support pipelines because there's no multitasking, but
I plan to hack that eventually by writing the output of one program to a file and providing the same file as input to the next.</p>
<p>There is also a compiler and assembler that runs inside the OS, although no peephole optimiser yet.
There are a lot of bugs, but also a lot of it works. Here's an
example session, showing a bit of command-line usage, and writing and running a program:</p>
<p><script id="asciicast-ps9jgqD0lJsiurxcXpiJ658EE" src="https://asciinema.org/a/ps9jgqD0lJsiurxcXpiJ658EE.js" async></script>
<small>(Spot the <a href="https://github.com/jes/scamp-cpu/commit/f8eb0800213e85af3b9d62459b4257c608166223">deliberate mistake</a> in the glob expansion!)</small></p>
<p>That session was recorded with the emulator running at maximum speed (so, about 20 MHz), and additionally with idle time of more
than 5 seconds removed, mainly the compiler.</p>
<p>Compiling software is painfully slow. It takes over 1 minute to compile any program that
includes <tt>stdio.sl</tt>. On real hardware that will take over 20 minutes, which is too slow to be tolerable, so I'll
need to do something about it. I have several ideas for improvements but haven't yet done enough profiling to work out what's best, and
getting new stuff <i>working</i> is currently more of a priority than getting it <i>fast</i>.</p>
<p>Writing a text editor is probably the next important step on the software side, so that I don't have to write code correctly, first-time,
top-to-bottom, with <tt>cat</tt>. Obviously I don't <i>really</i> need an editor, because I always get the code right the first time and
can easily write it in a straight line top-to-bottom...</p>
<p>The <a href="https://viewsourcecode.org/snaptoken/kilo/">Build Your
Own Text Editor</a> tutorial walks you through the implementation of Salvatore Sanfilippo's <a href="https://github.com/antirez/kilo">kilo</a> editor
(so named because it is less than 1000 lines of C). Another potential source of inspiration is David Given's <a href="https://github.com/davidgiven/cpmish/blob/master/cpmtools/qe.c">qe</a>
editor for CP/M, which uses an interesting <a href="https://en.wikipedia.org/wiki/Gap_buffer">gap buffer</a> data structure to store the text.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/scamp-lives.html</link>
   <guid>http://incoherency.co.uk/blog/stories/scamp-lives.html</guid>
   <pubDate>Sun, 21 Mar 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Bangle.js open source hackable smart watch: first impressions</title>
   <description><![CDATA[Bangle.js is an open source hackable smart watch running the Espruino
JavaScript interpreter. It includes BLE (Bluetooth Low Energy), heartrate monitor, temperature sensor, 3-axis accelerometer, GPS, compass, and touchscreen (ish), and
is designed to be easy to program.]]></description>
   <content:encoded><![CDATA[<p><a href="https://banglejs.com/">Bangle.js</a> is an open source hackable smart watch running the <a href="https://www.espruino.com/">Espruino</a>
JavaScript interpreter. It includes BLE (Bluetooth Low Energy), heartrate monitor, temperature sensor, 3-axis accelerometer, GPS, compass, and touchscreen (ish), and
is designed to be easy to program.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3267"><img src="https://img.incoherency.co.uk/3267/thumb"></a></p>
<p>I like the watch. It does exactly what is claimed: it is easy to program using the Espruino IDE. The battery lasts
a surprisingly long time (seems like at least 5 days between charges). The display is surprisingly high-resolution: 240x240 pixels doesn't sound like
a lot, but it's more than enough for an LCD that is only 24mm wide. It tells the time. Great success, just what I was after.</p>
<p>It costs about &pound;70 which, depending on your perspective, is either a lot of money or not a lot of money to pay for a watch.</p>
<p><h2>Comparison to Moto 360</h2></p>
<p>Last year I bought a secondhand Moto 360 to run <a href="https://asteroidos.org/install/smelt/">AsteroidOS</a> on. I
ended up regretting that purchase and selling the watch. The Moto 360 runs a full-blown Linux system (!), and has substantially more memory and a more powerful CPU than Bangle.js. It
has a (almost) circular display with full touch support. On paper, it's better than Bangle.js in almost every way.</p>
<p>In practice, the battery only lasted about a day, and the development workflow was just
<b>so</b> annoying and time-consuming that I couldn't be bothered with anything more than "Hello world". To connect the Moto 360 to the PC, you need to prise off the (glued) back cover and solder USB
wires on to the PCB, then plug it into the PC, work out how to get networking working over a USB modem, develop your program using Qt and QML,
then install it to the watch over SSH. Then undo your soldering and stick the back cover back on. Such a hassle. And that's <i>after</i> you've got past the step of replacing the stock OS with AsteroidOS!</p>
<p>AsteroidOS is a great project, but developing for it is more of a time investment than I'm after.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2799"><img src="https://img.incoherency.co.uk/2799/thumb"></a><br>
<small>(<i>To be clear:</i> this picture shows how you connect to the Moto 360; the watch pictured here is <b>not</b> the Bangle.js)</small></p>
<p>Bangle.js is the antithesis of the Moto 360 experience. It's simple. Easy to use and easy to program, and you don't have to feel like you're doing something "naughty" just by trying to run your own code on your own device. I've
already fixed a bug in an app I downloaded, and I haven't had to flash the firmware, break-and-enter past a glued-on cover, or even get my soldering sponge wet.
Bangle.js for the win.</p>
<p><h2>Hardware</h2></p>
<p>The watch is quite big, but not intolerably so. Here's a picture of it next to the watch I've been wearing for the past 7 or so years:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3268"><img src="https://img.incoherency.co.uk/3268/thumb"></a><br>
<small>(The pictured watchface is <a href="https://github.com/espruino/BangleApps/tree/master/apps/mclockplus">Morphing Clock Plus</a>)</small></p>
<p>It felt <i>very</i> big at first, but I got used to it quite quickly.</p>
<p>I'm not quite sure what the "N,E,S,W" markings on the bezel are for. They can't be rotated, and seem to bear no relation to anything else.</p>
<p>The screen can sense touch, but only in 2 zones. A touch on the left half of the screen is communicated to software as a press of "BTN4", and the
right half is "BTN5". This is <i>OK</i>, and is sufficient to detect swiping left and right, but it would obviously be better if it could sense a
grid of 16 or so zones instead of just left vs right.</p>
<p>The weirdest part of the watch is that the screen is actually square, despite the circular housing. I think this is an improvement over making a watch with a square housing,
but obviously it would be better if the display were circular as well. I guess circular displays were too expensive or inconvenient to procure.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3269"><img src="https://img.incoherency.co.uk/3269/thumb"></a><br>
<small>(The pictured watchface is <a href="https://github.com/espruino/BangleApps/tree/master/apps/animclk">Animated Clock</a>)</small></p>
<p>The watch has a really nice and convenient magnetic charging connector, but it seems like a slightly flawed design. The charging cable has a sticker on it warning you to
plug the connector in the right way around! The connector itself is totally symmetrical, so it is just as easy to plug it in backwards as forwards. It does
not specify what happens if you plug it in backwards, and I'm too afraid to try. Hopefully it just doesn't charge, rather than damaging anything.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3277"><img src="https://img.incoherency.co.uk/3277/thumb"></a></p>
<p>(In case you lose your sticker and need to find out which way around it goes: try to remember "the wire goes the same side as the buttons")</p>
<p>The instructions that came with the watch also cautioned against leaving the USB cable plugged in while the watch is not charging, because the magnets and the exposed
pins mean the connector is almost perfectly designed to seek out nearby conductive objects and short itself out on them! There is a laser-cut
<a href="https://shop.espruino.com/banglejs-dock">charging dock</a> available on the Espruino shop. This seems like a good candidate for 3d printing, and indeed
there are <a href="https://www.thingiverse.com/search?q=bangle.js&type=things&sort=relevant">various designs</a> available on Thingiverse.</p>
<p>I found that the watch is very slow to get a GPS fix. After 3 minutes of waiting, <a href="https://github.com/espruino/BangleApps/tree/master/apps/beer">Beer Compass</a>
still couldn't tell me the direction to the nearest pub:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3271"><img src="https://img.incoherency.co.uk/3271/thumb"></a></p>
<p>I expect the GPS will work better outdoors. Although, it's not like the pubs are open at the moment anyway.</p>
<p>I also found that the BLE range is surprisingly short. I have a Bluetooth dongle which I use for wireless headphones, and I can walk most of the way around the house and still hear my music
playing. But for some reason, I can't program the Bangle.js unless I hold the watch within about 30cm of the dongle. The BLE range on the watch is not sufficient to reach from my keyboard to the
PC under my desk. I don't know why.</p>
<p><h2>Firmware</h2></p>
<p>The LCD configuration is quite comprehensive. It gives very fine-grained control over the circumstances in which the screen will wake up, including automatically
detecting when you rotate your wrist towards your face. I'm not sure what units the "Twist Threshold" and "Twist Max Y" settings are in, or even exactly what they mean,
or which direction is positive, which makes these particular settings less useful than they could be.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3275"><img src="https://img.incoherency.co.uk/3275/thumb"></a></p>
<p>It also seems as though the "Timeout" settings, despite having no labelled units, are in different units. "LCD Timeout" is set to 10, and the LCD switches off after
10 seconds. But "Twist Timeout" is set to 1000, and it seems more likely that this is looking for twists that are shorter than 1 second rather than 16 minutes.</p>
<p><h2>Apps</h2></p>
<p>There are quite a few apps for the watch available on the <a href="https://banglejs.com/apps/#">Bangle.js App Loader</a>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3273"><img src="https://img.incoherency.co.uk/3273/thumb"></a></p>
<p>Unfortunately the apps do not include screenshots. I guess this is because it's inconvenient to take screenshots of the watch, and the Bangle.js ethos seems to be all about
lowering the barrier to entry, so requiring screenshots would be too much work. It's a shame, though, because it makes it hard to know whether you want to use
something without installing it first. Fortunately, the barrier to entry to <i>installing</i> apps is also pretty low, so it's not too hard to just test out
everything that looks interesting and keep the ones you want.</p>
<p>One effect of the low barrier to entry is that some of the apps are not as polished as you might be used to. This is related to something I <a href="https://incoherency.co.uk/blog/stories/making-stuff.html">wrote
about before</a> in the context of 3d printing:</p>
<p><blockquote>If you spend some time browsing <a href="https://www.thingiverse.com/">Thingiverse</a> then you might notice that some of the parts are designed very strangely. Parts that have sharp and
square edges where rounded edges would look neater, thinner or thicker than appropriate, strength in the wrong places, inappropriate fasteners, and so on.</p>
<p>Your first reaction might be "this is clearly bad, these people are no good at designing things". I think the opposite way of looking at it is more useful:
<b>people with no training or experience are now able to design and produce parts that successfully solve their problems.</b> It's not that designing for 3d printing
results in worse parts, it's that the barrier to entry for design of working parts is much lower than it ever has been in the past. And I think that is a good
thing.</blockquote></p>
<p>Exactly the same effect is apparent in Bangle.js, and I still think it's a good thing.</p>
<p>One example of an under-polished app is the <a href="https://github.com/espruino/BangleApps/tree/master/apps/counter">Counter</a> app. It helps you count things. A number is displayed in
the centre of the screen, and you can increase it or decrease it using the side buttons or the touchscreen.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3274"><img src="https://img.incoherency.co.uk/3274/thumb"></a></p>
<p>It <i>worked</i>, and was perfectly adequate for counting things. But I noticed that when the "widgets" at the top of the screen are hidden, the counter disappears. Eh? Also, the counter is
sometimes displayed in the colour of one of the widgets instead of white.</p>
<p><h2>Development</h2></p>
<p>Fortunately, the low barrier to entry of the Bangle.js ecosystem allowed me to quickly and easily <a href="https://github.com/jes/BangleApps/commit/37c87286968c4c2bc0e46daea20aa69a1d70d450">fix these problems myself</a>.
(The bug was that the app only set the drawing colour once at startup, instead of every time it draws the screen - if the widgets are redrawn and leave black as the active colour, then
the counter information is drawn in black as well, and similarly if the widgets leave another colour active then the counter is drawn in that colour).</p>
<p>I was disappointed to find that the Espruino web IDE can't connect to the watch from Firefox. You need to use Chromium. The reason is that Firefox does not implement "Web Bluetooth". I think
I'd prefer a local development envrionment to a web IDE anyway. There is an <a href="https://www.npmjs.com/package/espruino">espruino CLI tool</a>, but it's "very javascript", which means it
has a million dependencies, and half of them consider various parts of my system deprecated and therefore don't work properly.</p>
<p>It is possible to run the web IDE locally in electron, which I'll probably look into.</p>
<p>I know that I want to write some apps to run on the watch, but I haven't yet figured out what I want them to do. I think a <a href="https://incoherency.co.uk/blog/stories/chess-clock.html">chess clock</a> watch face might be doable, if
not entirely practical. I also think a <a href="https://incoherency.co.uk/blog/stories/seasonal-css.html">seasonal</a> clock face might be fun.</p>
<p>I'm not completely sure about the state of the BLE security. It seems as if the default condition of the watch is 100% open, and anybody within (the admittedly short!) bluetooth range can run arbitrary code
on the watch with no user interaction required. I think it might be useful to write an app for the watch that keeps BLE switched off except when explicitly connected, and times out after 30 minutes or so.
You'd then perform some incantation to tell it you want BLE on, and it would allow BLE for 30 minutes before switching it off again.
There is a setting in the menu to turn off BLE, but if you forget to turn it off, you're obliviously walking around with arbitrary remote code execution on your wrist. There is an option in the
menu to whitelist specific devices:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3276"><img src="https://img.incoherency.co.uk/3276/thumb"></a></p>
<p>But I don't know enough about BLE to know if this is foolproof (e.g. can you spoof it? how long does it take to brute-force the set of all likely device IDs? I should look into this).
Regardless, I'd be more comfortable with BLE simply <b>off</b> while not in use.</p>
<p><h2>Conclusion</h2></p>
<p>Running JavaScript on a microcontroller is a really interesting way to make hackable devices. Compared to native machine code programs, the JavaScript model makes it substantially
easier for unrelated apps to coexist happily, and even run at the "same" time (e.g. the widgets). Nothing is going to trample over the top of the memory of another app when it isn't working directly with pointers, and nothing
is going to hog the CPU when everything is event-driven (where an Arduino project would use a <tt>while</tt> loop, or the <tt>loop()</tt> function, Espruino apps use <tt>setInterval()</tt>).</p>
<p>The downside of running JavaScript is obviously the reduced performance and increased memory usage, but I think it is more than worth it. It's a perfect example of the
<a href="https://en.wikipedia.org/wiki/Worse_is_better">worse is better</a> model, applied to hardware design:</p>
<p><blockquote>
Hardware quality does not necessarily increase with
functionality: there is a point where less functionality ("worse") is a preferable
option ("better") in terms of practicality and usability. Hardware that is limited,
but simple to use, may be more appealing to the user and market than the reverse.
<small>from <a href="https://en.wikipedia.org/wiki/Worse_is_better">Wikipedia</a>, but with "software" changed to "hardware"
</blockquote>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/banglejs-first-impressions.html</link>
   <guid>http://incoherency.co.uk/blog/stories/banglejs-first-impressions.html</guid>
   <pubDate>Wed, 17 Mar 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Front panels for SCAMP</title>
   <description><![CDATA[I've put together the memory card for the SCAMP CPU, including the front panel with LEDs to show
the bus contents and address register.]]></description>
   <content:encoded><![CDATA[<p>I've put together the memory card for the SCAMP CPU, including the front panel with LEDs to show
the bus contents and address register.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3245"><img src="https://img.incoherency.co.uk/3245/thumb"></a></p>
<p>The SCAMP CPU won't have a "normal" front panel, where all the switches and lights are on a single panel at the front of the case.
Instead, each card will have its own panel, all visible at the front of the case.</p>
<p><h2>Design</h2></p>
<p>The first problem to solve is how to connect the panel to the card. I settled on 3d printing some brackets to take
2 brass threaded inserts. One would be used to screw the card to the bracket, and the other to screw the panel
to the bracket:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3252"><img src="https://img.incoherency.co.uk/3252/thumb"></a></p>
<p>I expect that the cards might be quite hard to pull out of the backplane, because the insertion force on a 60-pin
connector is considerable. For that reason, I wanted the front panels to be quite robust. I don't want to bend them
trying to unplug the cards. So I wanted to make the panels out of a 3mm plate. But my panel-mount LED holders call for a ~1mm panel:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3253"><img src="https://img.incoherency.co.uk/3253/thumb"></a></p>
<p>I made a few 3d printed test pieces and determined that they would actually fit nice and tightly in a 2mm panel, but that's
still not as thick as I would prefer, so my solution was to make 1.2mm deep stepped holes for the LED holders:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3254"><img src="https://img.incoherency.co.uk/3254/thumb"></a></p>
<p>That way we get the stiffness of a 3mm panel while presenting a 1.8mm interface to the LED holders. Arguably this is even
neater than the recommended installation, because it means the LED holders end up roughly flush with the panel surface instead of
sticking out.</p>
<p>With the mounting problems solved, it's just a case of modelling the part. I used <a href="https://www.freecadweb.org/">FreeCAD</a> as
usual, and all of the CAD files are in the <a href="https://github.com/jes/scamp-cpu/tree/master/front-panels">front-panels/</a> directory
in the git repo.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3251"><img src="https://img.incoherency.co.uk/3251/thumb"></a></p>
<p>You might notice that the holes are not quite equally-spaced. They're grouped into 4s to facilitate reading out hex.</p>
<p>The reason for the cut-out corner at the bottom on each side is that I plan to use that space to insert a lever tool of some sort to help unplug
the card. Or at minimum, to insert fingers. Again this is because I expect the cards to be quite hard to unplug, and I
want to make it as convenient as possible.</p>
<p>I've always found FreeCAD's text handling facilities are more trouble than they're worth, so I laid out the engraving in Inkscape
instead:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3250"><img src="https://img.incoherency.co.uk/3250/thumb"></a></p>
<p>The bulk of the work here was laying out a faithful reproduction of the outer profile and hole locations, to make sure it all lines up
properly. (Foreshadowing).</p>
<p>I used the <a href="https://www.evilmadscientist.com/2011/hershey-text-an-inkscape-extension-for-engraving-fonts/">Hershey Text</a>
Inkscape plugin to create the text, and "Path to Gcode" from the <a href="https://github.com/cnc-club/gcodetools">gcodetools</a> plugin
to turn it into G-code. This is a workflow I first learnt for engraving the text on Emma's <a href="https://www.worryknot.co.uk/collections/spinner-necklace">spinner pendants</a>.</p>
<p>Protip: you can <tt>cat</tt> multiple G-code files together and open the result in FreeCAD to ensure that everything looks like it is
going to work together in the same coordinate system:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3255"><img src="https://img.incoherency.co.uk/3255/thumb"></a></p>
<p>(Another protip: turn off the background colours in FreeCAD to look at G-code paths, because green on blue is hard to see).</p>
<p><h2>Cutting</h2></p>
<p>I thought about making the panels out of brass because it's more <a href="https://astralcodexten.substack.com/p/book-review-fussell-on-class">classy</a>, but
I already had a 3mm aluminium plate, so I used that instead.</p>
<p>I initially tried to cut it out using 2mm cutting tools, and had a very bad time. I kept breaking the tool, and do not completely know why.
After breaking the first couple of tools I tried to calculate correct feeds and speeds, but they were <i>way</i> faster than seems reasonable.
I tried it anyway, and the tool broke <a href="https://www.youtube.com/watch?v=cvulg0DBkXg">almost immediately</a>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3256"><img src="https://img.incoherency.co.uk/3256/thumb"></a></p>
<p>Having exhausted my supply of
2mm tools, I regenerated the G-code to use a 4mm tool, with some apprehension because I was not convinced my router is powerful enough to push a 4mm
tool through aluminium.</p>
<p>To my surprise, it worked perfectly on the first try. Incredible. I'll be using larger tools more often. They are more robust, and despite
having to remove more material, they also cut faster.</p>
<p>The 4mm tool is too large for the countersunk screw holes, so I spot-drilled those on the CNC machine and finished them by hand.</p>
<p><h2>Finishing</h2></p>
<p>To tidy up the worst of the burrs on the engraving, I left the part in sodium hydroxide (aka caustic soda) for about 10 minutes. In addition to dissolving the burrs, this leaves a nice
surface finish similar to sand-blasting.</p>
<p>To make the writing stand out better, I dripped a bit of paint into it and then rubbed off the excess with isopropyl alcohol. I haven't done a fantastic job of this, I will try
to do it better next time.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3239"><img src="https://img.incoherency.co.uk/3239/thumb"></a></p>
<p>Then put the LED holders in.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3240"><img src="https://img.incoherency.co.uk/3240/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3241"><img src="https://img.incoherency.co.uk/3241/thumb"></a></p>
<p>Push in the LEDs.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3242"><img src="https://img.incoherency.co.uk/3242/thumb"></a></p>
<p>Trim the leads and solder all the negative legs together.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3243"><img src="https://img.incoherency.co.uk/3243/thumb"></a></p>
<p>And solder the wires on.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3244"><img src="https://img.incoherency.co.uk/3244/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3246"><img src="https://img.incoherency.co.uk/3246/thumb"></a></p>
<p>I found that soldering the wires for the LEDs was extremely boring and time-consuming. I still have more than 80 left to do on the other cards (X register, Y register, ALU output,
instruction register, microinstruction), which I am not looking forward to.</p>
<p>I also found that one of the LEDs doesn't work, that's annoying:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3247"><img src="https://img.incoherency.co.uk/3247/thumb"></a></p>
<p>I will have to replace it.</p>
<p>I also noticed that the vertical lines in between the groups of LEDs aren't centred! I don't know how I managed this. What a blunder. I should have checked the G-code more carefully.
I'm not going to make it again though, I'll just live with it.</p>
<p><h2>Case</h2></p>
<p>I have done a little bit of thinking about the case. I think it might be nice to make it out of wood, with aluminium guide rails inside for the cards to slide on. I need
the case to hold the backplane at the back, hold guide rails at the sides, hold a power supply probably somewhere at the bottom, and protect the cards. I accept that
wood is not a very technical material, and perhaps not befitting of a CPU, but I think it would end up neater than anything I could come up with by trying to bend sheet metal. And it
might be nice.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/scamp-front-panels.html</link>
   <guid>http://incoherency.co.uk/blog/stories/scamp-front-panels.html</guid>
   <pubDate>Sun, 28 Feb 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The SCAMP kernel</title>
   <description><![CDATA[You might think it's a bit early to be working on an operating system, given that I don't have
a CPU to run it on. Maybe you're right. But working on software is easy and working on hardware
is time-consuming, so here we are.]]></description>
   <content:encoded><![CDATA[<p>You might think it's a bit early to be working on an operating system, given that I don't have
a CPU to run it on. Maybe you're right. But working on software is easy and working on hardware
is time-consuming, so here we are.</p>
<p>The current state of the kernel is that it can <i>read</i> files from a simple filesystem stored on an
emulated block device, exposing a roughly Unix-like API
(<tt>open()</tt>/<tt>read()</tt>/<tt>write()</tt>/<tt>close()</tt>), and assign file descriptors.
It can also use the filesystem API to load code from the disk and execute it as a user program
via <a href="https://github.com/jes/scamp-cpu/blob/a0c0fa4af9ba5b303667143e4341657ebd01ddd2/os/os_proc.sl#L20-L44">the <tt>exec()</tt> system call</a>.</p>
<p>It can't yet <i>write</i> to disk, and <tt>opendir()</tt>/<tt>readdir()</tt> are still
unimplemented, as is almost everything else, but I am making relatively good progress and with any luck the kernel will be
feature-complete pretty soon. Once the filesystem is done, there's not actually that much more to
add.</p>
<p>I'm not quite sure it's considered correct to call it a "kernel", given that the SCAMP CPU has
no memory management unit and no concept of user mode vs kernel mode. I'm calling it a "kernel"
anyway in the absence of a better term.</p>
<p>Currently, the boot process is as follows:</p>
<p><ol>
<li>the bootloader in ROM loads the kernel from the start of the disk and jumps to it</li>
<li>the kernel initialises the block device and file descriptor table, and calls
<tt>exec(["/bin/init"])</tt></li>
<li><tt>exec()</tt> uses the filesystem API to read <tt>/bin/init</tt> into memory starting
at 0x100, and then jumps to it</li>
<li><tt>init</tt> reads <tt>/etc/motd</tt> and writes it to the console</li>
<li><tt>init</tt> halts, in the absence of anything else to do</li>
</ol></p>
<p>Eventually <tt>init</tt> might be replaced by a shell script so that it can be more conveniently
changed. The ultimate goal of <tt>init</tt> is to start a shell, but I haven't got that far yet.</p>
<p>Here's an <a href="https://asciinema.org/">asciinema</a> recording of the SCAMP system booting in
the emulator,
with an emulated clock speed of 500 kHz. I don't actually know what clock frequency the real hardware
will be able to run at, but I hope 500 kHz is achievable.</p>
<p><script id="asciicast-yCdJT8LfmyrL0D80NxrrwuXcY" src="https://asciinema.org/a/yCdJT8LfmyrL0D80NxrrwuXcY.js" async></script></p>
<p>(The jerky <tt>motd</tt> output is because it reads a block, writes it to the console, read the
next block, writes it to the console, and so on - there's a pause in between each block).</p>
<p>The kernel is mostly implemented in <a href="https://incoherency.co.uk/blog/stories/slang.html">SLANG</a>, with inline
assembly code where necessary. I expect more of it will turn into inline assembly code when
the practical bottlenecks are identified. You can read the code <a href="https://github.com/jes/scamp-cpu/tree/d69789d3ff25eb3101d4aea5edb258e900b2ba9f/os">in the os/ directory</a> of the git repo. Or
try it out if you can work out how to build it! I'll help you if you want.</p>
<p>The kernel is about 8K words of code, while init is 3K and <tt><a href="https://www.eff.org/cyberspace-independence">/etc/motd</a></tt> is about 5K. You may therefore be surprised that in the
screen recording, the kernel loads in about 2 seconds while <tt>init</tt> doesn't produce any
output for about 10 seconds, and then seems to <i>very</i> slowly write the contents of the
text file. The reason is that the bootloader loads the kernel with a short, special-purpose piece
of assembly code, while the rest of it is both more general, and written in SLANG. I expect it
won't be hard to improve the SLANG parts, but I don't want to waste time on it yet.</p>
<p>Executables work the same way as in CP/M. The contents of a file are loaded into memory starting
at 0x100 and then jumped to. There's no header on the file, and no support for dynamic linking etc.,
it just contains raw memory contents.</p>
<p>The OS design is kind of a bastard child of CP/M and Unix. It has a Unix-like system call API
and filesystem layout, but CP/M-like capabilities. It has the simplicity that I love from CP/M,
and the API that I love from Unix. But is also worse and less capable than both. Swings and
roundabouts.</p>
<p><h3>System calls</h3></p>
<p>Each system call is accessed by calling a function pointer in a table stored just below the
pseudoregisters (i.e. addresses up to 0xfeff). <tt>exit()</tt>'s pointer is stored at 0xfeff,
so to call <tt>exit(0)</tt> in assembly language, something like this would work, where
parentheses indicate indirection:</p>
<p><pre><code>push 0
call (0xfeff)</code></pre></p>
<p>The system call references is in <a href="https://github.com/jes/scamp-cpu/blob/master/doc/SYSCALLS.md">doc/SYSCALLS.md</a>.
Most of them are not implemented yet, I'm mostly working my way through
implementing them in the order that I come across a need for them.</p>
<p>Compared to the normal Unix system calls, the main surprising differences are:</p>
<p><ul>
<li><tt>system()</tt> is a system call instead of a wrapper around <tt>fork()</tt>/<tt>exec()</tt>:
this is part of my plan for suspending the running process and replacing it with a child</li>
<li><tt>fork()</tt> is missing: we won't support it</li>
<li><tt>ioctl()</tt> is missing: so far I have no use for it, but it might appear eventually</li>
<li><tt>sbrk()</tt> is missing: this is implemented in "user space" instead, since the user program
always owns all of the memory, up to the start of the kernel</li>
<li><tt>dup()</tt> is missing: there's a comparable but better system call named <tt>copyfd()</tt> (which
is actually roughly the same as <tt>dup2()</tt>, maybe I should rename it)</li>
<li>we gain an <tt>osbase()</tt> call that reports the start address of the kernel, and a
<tt>cmdargs()</tt> that supplies command-line arguments</li>
</ul></p>
<p>And besides that, anything related to networking, pipes, user accounts, file permissions, date/time,
IPC, and signals doesn't exist because these concepts don't exist.</p>
<p><h3>Filesystem</h3></p>
<p>The filesystem is the vast majority of the kernel. Having implemented some of it,
it has become very clear why DOS is called a "disk-operating system". Operating the disk is
basically all you need to do.</p>
<p>Fitting the theme of the rest of the project, the filesystem is about the simplest workable solution
I could
think of. It assumes a 512-byte block size, which I know to be correct for SD cards,
and I expect won't be too much of an impediment for CompactFlash. It supports 16-bit block
numbers, which means up to 65536 blocks or 32 MBytes.</p>
<p>Blocks 0 to 63 are unused: these are available for the kernel to be stored in. I don't
expect to need a full 32 KBytes for the kernel, but I at least shouldn't ever have to relocate the
filesystem.</p>
<p>The next 16 blocks are a free-space bitmap for the entire disk (including the first 80 blocks, for
sake of simplicity). Each block on the disk is represented by 1 bit in the free-space bitmap. When
a new block is needed, the free-space bitmap is linear-searched until a free space is found.</p>
<p>Block 80 (the root directory block) and onwards are the filesystem contents. Each of these blocks
begins with a 4 byte header encoding:</p>
<p><ul>
<li>(6 unused bits)</li>
<li>1 bit: block type: directory=0, file=1</li>
<li>9 bits: length of block contents</li>
<li>16 bits: "next" block pointer</li>
</ul></p>
<p>When the contents of a file or directory are too long to fit in 1 block, the rest of the contents
are in the block pointed to by the "next" field, forming a linked list of blocks. A "next"
pointer of 0 indicates that this block is the last one for the file.</p>
<p>A directory block contains 15x 32-byte directory entries, with 28 bytes wasted at the end of the
block. (Maybe I should change this to 33-byte directory entries to gain an
extra character in filenames for free.)</p>
<p>A directory entry is just a filename (1 to 30 bytes) and a block pointer (2 bytes). There is
no support for symlinks, reference counting, permissions, atime/ctime/mtime, etc. as these things
are not necessary. Unused directory entries are indicated by having an empty filename.</p>
<p>I think the filesystem is a substantial improvement over the CP/M filesystem, because it supports
directories, supports longer filenames than 8-dot-3, and supports files with a content length that
is not a multiple of the block size. In
CP/M, text files that don't end on a block boundary are suffixed with a load of <tt>^Z</tt>, because
<tt>^Z</tt> means EOF in CP/M. That said, my filesystem API only exposes word-aligned access to
file contents, which means files with an odd number of bytes will probably end up with a spurious
trailing 0 byte anyway...</p>
<p><h3>Exception handling</h3></p>
<p><i>longjmp is my goto</i>.</p>
<p>I am quite fond of the kernel's exception handling mechanism. Each system call that needs to
handle exceptions starts with:</p>
<p><pre><code>var err = catch();
if (err) return err;</code></pre></p>
<p><tt>catch()</tt> returns 0, but if anything, anywhere down the call stack, subsequently calls
<tt>throw(err)</tt>, then the <tt>err</tt> value
will magically pop out of <tt>catch()</tt> and the system call will return the error to user
space. Pretty neat, no?</p>
<p>It is based on the
<a href="https://man7.org/linux/man-pages/man3/setjmp.3.html"><tt>setjmp()</tt>/<tt>longjmp()</tt></a>
"nonlocal goto" mechanism from C.</p>
<p>You give <tt>setjmp()</tt> a pointer to a "<tt>jmp_buf</tt>", which stores information about
the calling environment (stack pointer, return address, other registers etc. depending on the
system). On the first call, <tt>setjmp()</tt> returns 0.</p>
<p>When you subsequently call <tt>longjmp()</tt> with the same <tt>jmp_buf</tt>, it restores the
saved state and returns a nonzero value back to the place that first called <tt>setjmp()</tt>.
It acts exactly as if control had magically transferred back to <tt>setjmp()</tt>, which then
returns a new value.</p>
<p>I love the idea of <tt>longjmp()</tt> but have never had a substantial excuse to use it before.
<a href="https://github.com/jes/scamp-cpu/blob/bf1291e4ac4ad53d574699a77bd32be7baab5a14/os/util.sl#L178-L237">The implementation</a> is surprisingly straightforward, although there are some caveats:</p>
<p><ul>
<li>if you try to use <tt>longjmp()</tt> to return control to a function that has already returned,
then that function's stack frame is gone, potentially replaced with anything, and it will fail
in surprising ways</li>
<li>(in SLANG, but not necessarily in C) if you try to use <tt>setjmp()</tt> inside an expression (e.g. <tt>var n = 10 + catch()</tt>), then the other parts of the
expression that should have been pushed onto the stack will not be there any more and it will fail in surprising ways</li>
</ul></p>
<p>The man page says:</p>
<p><blockquote>While it can be abused, the traditional C "goto" statement at
least has the benefit that lexical cues (the goto statement and
the target label) allow the programmer to easily perceive the
flow of control.  Nonlocal gotos provide no such cues: multiple
setjmp() calls might employ the same jmp_buf variable so that the
content of the variable may change over the lifetime of the
application.  Consequently, the programmer may be forced to
perform detailed reading of the code to determine the dynamic
target of a particular longjmp() call.  (To make the programmer's
life easier, each setjmp() call should employ a unique jmp_buf
variable.)
<br><br>
Adding further difficulty, the setjmp() and longjmp() calls may
not even be in the same source code module.
<br><br>
In summary, nonlocal gotos can make programs harder to understand
and maintain, and an alternative should be used if possible.</blockquote></p>
<p>Even though my use case involves multiple different <tt>catch()</tt> calls with the same
<tt>jmp_buf</tt>, and even though the <tt>catch()</tt> and <tt>throw()</tt> calls are
not always in the same source module, I don't think it's too hard to understand. <tt>throw(err)</tt>
always passes an <tt>err</tt> to the top of the current system call.</p>
<p>There is a slight footgun, in that if I forget to call <tt>catch()</tt> in a system call that
can trigger a <tt>throw()</tt>, then we're in the case of "trying to return control to a function
that has already returned" (i.e. the last system call that <i>did</i> call <tt>catch()</tt>),
and it will fail in surprising ways. I'll just try not to do that.</p>
<p><h3>Kernel profiling</h3></p>
<p>Profiling the kernel works just like any other program: run it in the emulator with <tt>-p</tt>,
and look at the generated HTML report.</p>
<p>Since I last wrote about <a href="https://incoherency.co.uk/blog/stories/slang.html">the profiling tool</a>, I have added
a killer new feature: it now resolves addresses to symbols!</p>
<p>The report generator can now take in the annotated hex output produced by the assembler,
extract symbol names from the comments, and annotate memory addresses with the symbol they are
associated with:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3248"><img src="https://img.incoherency.co.uk/3248/thumb"></a></p>
<p>This basically automates the task of finding a hotspot in memory, looking at the address, then
searching through the annotated hex to find out which function is resident at that address.</p>
<p>It knows how much time is spent executing each function, and gives a breakdown of how many
cycles were spent in each one, which is really useful for directing optimisation efforts. In
the screenshot above, you can see that 58% of execution time was spent inside the <tt>blkread()</tt>
function, which probably means that is a prime candidate for reimplementing in assembly language.</p>
<p>Just by looking at the length of "red" addresses in <tt>blkread()</tt>, you can see that it's
not reading data very efficiently. In the ideal case, reading a 512-byte block from the block device
would execute a single <tt>in</tt> instruction 512 times, but it looks like the function
is doing quite a lot of work besides that.</p>
<p>Similarly <tt>memcpy()</tt> is used a lot and would benefit from a more efficient implementation.</p>
<p>If you want, you can look at the current <tt><a href="https://github.com/jes/scamp-cpu/blob/df517d2e5f9b3a75a7a80d48c8a5d5c082eca26c/os/blkdev.sl#L8-L24">blkread()</a></tt> and <tt><a href="https://github.com/jes/scamp-cpu/blob/bf1291e4ac4ad53d574699a77bd32be7baab5a14/os/util.sl#L60-L64">memcpy()</a></tt> implementations. Neither of these implementations are inherently bad, it's just that the compiler is a bit
of a blunt instrument at the moment.</p>
<p><h3>Bad bits</h3></p>
<p>Currently the block device and serial port don't actually represent any real hardware, they're just
placeholders that allow me to develop the rest of the system using the emulator. Eventually
I do want it to work with real hardware, and at that point I'll probably make the emulator match
the hardware.</p>
<p>In Unix, IO devices are represented by device files like <tt>/dev/ttyS0</tt>, and if you
want to write to a particular device, you can open the device file to get a file descriptor
for it. I don't <i>think</i> I want to bother supporting device files, because the only devices
I'll have are the block device for the filesystem and the serial ports. So for now I am just
hard-coding file descriptor 3 to be the serial port for the console. For example, to explicitly
connect stdin/out to the serial port, you can use the <tt>copyfd()</tt> call:</p>
<p><pre><code>copyfd(0, 3); # stdin on fd 0
copyfd(1, 3); # stdout on fd 1</code></pre></p>
<p>Similarly, you can connect stdin/out to a file on the disk by using <tt>copyfd()</tt> with the
file's fd instead of 3.</p>
<p>Currently the kernel and the user space library both contain identical implementations of
common functions like <tt>memcpy()</tt> etc.
There's not a lot of point wasting memory on 2 copies of the same function, so I'd like
to come up with a good way to share these. Perhaps I should just make them into system calls. The
system call overhead is precisely the same as that of a normal function call, so this wouldn't incur
any performance penalty. The only downside is that it means you need to rebuild the kernel if you
want to change the implementation. Although the upside is that all the user space programs get the
improved version for free <i>without</i> being recompiled.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/scamp-kernel.html</link>
   <guid>http://incoherency.co.uk/blog/stories/scamp-kernel.html</guid>
   <pubDate>Sat, 27 Feb 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>A compiler for SCAMP, and machine code profiling</title>
   <description><![CDATA[I've been working on a compiler for the SCAMP CPU. It compiles a language I'm calling "SLANG" (which just stands
for "SCAMP Language" pending a better backronym) into SCAMP assembly language.]]></description>
   <content:encoded><![CDATA[<p>I've been working on a compiler for the SCAMP CPU. It compiles a language I'm calling "SLANG" (which just stands
for "SCAMP Language" pending a better backronym) into SCAMP assembly language.</p>
<p>You can view SLANG as a "slightly less-safe C", without arrays, structs, or unions, and a bit easier to parse.</p>
<p>If you want, you can look through the current <a href="https://github.com/jes/scamp-cpu/blob/f260f52d950be90c2279f584d0e2183ae6c986b4/compiler/slangc">Perl implementation
of the SLANG compiler</a>, or the <a href="https://github.com/jes/scamp-cpu/blob/f260f52d950be90c2279f584d0e2183ae6c986b4/compiler/slangc.sl">SLANG-in-SLANG implementation</a>.
They are both structured the same: read the source into memory, and parse it with a hand-written recursive-descent parser, printing
assembly code to stdout during parsing. The Perl implementation only exists for bootstrapping purposes.</p>
<p>I've also added a "profiling" feature to the <a href="https://github.com/jes/scamp-cpu/blob/f260f52d950be90c2279f584d0e2183ae6c986b4/emulator/scamp.c">SCAMP emulator</a>. This
collects data on how much time is spent at each address, how much time is spent on each instruction opcode, and how many reads/writes are done to each address, and generates
HTML reports like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3230"><img src="https://img.incoherency.co.uk/3230/thumb"></a></p>
<p>(I would link to an example, but it's about 35M of HTML so only really useful for local viewing - it contains multiple large tables each containing tens of thousands of cells! But there
is some easy low-hanging fruit, like encoding the cell background colours using 100 or so classes with short names, rather than <tt>style="background-color:rgba(...)"</tt> for every single one.
Maybe I'll fix that at some point, but it's not a problem for me at the moment.)</p>
<p>The time spent adding the profiling feature was of extraordinarily high value, because it immediately revealed 1 stupid performance bug in the SLANG compiler,
and 2 "unintended code execution" bugs (1 a silly compiler bug, 1 a fun microcode bug) that might have been quite difficult to debug had they ever caused a problem.</p>
<p>This is another long post. If you only want to read 1 section, I'd suggest ctrl-f for "subtle microcode bug".</p>
<p><h2>SLANG</h2></p>
<p><a href="https://dartoxia.com/">Ben</a> tells me that Goldman Sachs use Slang internally and
<a href="https://www.efinancialcareers.co.uk/news/2018/09/slang-programming-job-goldman-sachs-technology-career-killer">Some
Goldman programmers say they love Slang</a>. So at least I've got that going for me.</p>
<p>Github thinks SLANG code is actually "Slash", presumably based on the file extension (I'm using <tt>.sl</tt>):</p>
<p><a class="img" href="https://img.incoherency.co.uk/3232"><img src="https://img.incoherency.co.uk/3232/thumb"></a></p>
<p><h3>Types</h3></p>
<p>SLANG only has one type. It's called "var" and it stores a 16-bit word. This can be a signed or unsigned integer value, or a pointer to anything
you want, including a function. Functions don't directly exist as a type of thing, only function pointers exist. Declaring a function in SLANG results in an expression
that yields a pointer to the function, so functions are declared like this:</p>
<p><pre><code>var f = func(x) {
    return x+5;
};</code></pre></p>
<p>This also trivially allows anonymous functions, you can imagine something like:</p>
<p><pre><code>sort(array, array_length, func(a,b) { return a&lt;b });</code></pre></p>
<p>Only having function pointers, and only 1 type of "var", means there are no function signatures.
When you call <tt>f(x)</tt> there is nothing that is actually checking (either at compile time or runtime) that you've passed
the right number of arguments. And if you pass the wrong number of arguments, then the stack pointer will be in the wrong place when the function returns, and
everything will go off the rails in confusing and hard-to-debug ways. All just part of SLANG's charm :).</p>
<p>The fact that the only way to call a function is via a function pointer also means that there is an extra level of memory indirection on every single function call, compared to
what a C compiler would do. I don't mind though. It only costs 1 extra clock cycle.</p>
<p><h3>Array indexing</h3></p>
<p>There is also no array indexing syntax, but there is pointer arithmetic. Array accesses look like <tt>*(array+index)</tt> (incidentally, in C, <tt>array[index]</tt> is
defined to be equivalent to <tt>*(array+index)</tt> - I may eventually add similar syntactic sugar). By way of an example, here's a possible implementation of <tt>puts()</tt>:</p>
<p><pre><code>var puts = func(s) {
    var i = 0;
    while (*(s+i)) {
        putchar(*(s+i));
        i++;
    };
};</code></pre></p>
<p>Although the one I'm currently using is a little bit shorter:</p>
<p><pre><code>var puts = func(s) {
    while (*s) 
        putchar(*(s++));
};</code></pre></p>
<p>By convention, a string is a nul-terminated array of characters, just like in C, so <tt>puts()</tt> just passes each character to <tt>putchar()</tt> until it reaches a character
that is 0.</p>
<p><h3>Semi-colons</h3></p>
<p>The grammar around semi-colon placement is slightly different to C. A trailing semi-colon on the last statement of a block is optional. While loops and if statements
are considered single statements, and require a trailing semi-colon (unless they're the last statement in a block) even if braces are used:</p>
<p><pre><code>if (x == 5) {
    puts("This line needs a semi-colon\n");
    puts("This line doesn't\n")
}; # This one does
puts("foo\n") # This one doesn't, assuming it's the last line in its block</code></pre></p>
<p><h3>Parsing</h3></p>
<p>Through serendipitous timing, <a href="https://norswap.com/">Nicolas Laurent</a> released the recorded video lectures for his 2021
<a href="https://norswap.com/compilers/">compilers course</a> just as I was getting around to
starting on the compiler. I watched the first few of his videos and found <a href="https://www.youtube.com/watch?v=Ytq0GQdnChg">5. Writing Parsers by Hand</a>
particularly useful. I copied the structure of his recursive-descent parser when writing the SLANG compiler: the input is slurped into memory, with
a global value storing a "cursor" location, and each parsing function either matches, which means it consumes the input characters that it matched, updates the cursor,
and returns 1, or it doesn't match, which means it leaves the input cursor alone and returns 0. This interface makes it very easy to reason about the parser. I gather
that the later lectures are more about using a parser generator, which is not ideal for my use case, because then I'd need to write the parser generator <i>as well as</i> the
compiler. I still plan to watch the rest of the series as I'm sure there will be plenty of useful stuff to learn.</p>
<p><h3>Code generation</h3></p>
<p>I also found <a href="http://cowlark.com/">David Given</a>'s video <a href="https://www.youtube.com/watch?v=iUarU8Fhvug">Hjalfi writes a compiler</a>, in which he
writes a <a href="http://cowlark.com/cowgol/">Cowgol</a> compiler, quite useful. It's an 8-hour-long
narrated screen recording. I didn't watch the whole thing, and didn't watch all I did watch in one sitting, but I watched enough to learn a lot.
He uses lex/yacc to do the parsing, but the key insight I got was the idea of emitting code immediately as the input is parsed, rather than generating an abstract syntax tree
in memory and then turning that into code later.</p>
<p>Parsing each term of an expression generates code to push its value onto the stack, and parsing an operator generates code to pop 2 arguments off the stack, apply the operator,
and push the result onto the stack. Helper functions are used to generate code to push the values of named variables (which can either be globals, at fixed addresses, or locals, which are stored
on the stack, and accessed relative to a stack frame base pointer), and to store the top value of the stack to a named variable.</p>
<p>You can kind of view the parser's call graph as an implicit AST.</p>
<p><h3>Optimisation</h3></p>
<p>One of the weird things about this kind of compiler is that it turns something like <tt>var foo = 5;</tt> into:</p>
<p><pre><code>push 5
pop x
ld (_foo), x</code></pre></p>
<p>instead of simply <tt>ld (_foo), 5</tt>. The reason is that the code that is responsible for parsing "5" has absolutely no idea what context it is to be used in. It just
parses a numeric literal and generates code to push it onto the stack. This results in a simple compiler, but particularly awful code. Fortunately, it is quite easy to
clean up after-the-fact with a <a href="https://en.wikipedia.org/wiki/Peephole_optimization">peephole optimiser</a>, which is another idea I first learnt from David Given.
The idea is to go over the generated assembly code applying simple optimisation rules to very short localised sections. A particularly effective example is
that <tt>push x</tt> followed immediately by <tt>pop x</tt> is a no-op, so you can safely delete both instructions. The generated code doesn't do <i>precisely</i> the same
thing (because the value in the X register should have got put on the stack just below the stack pointer) but for the code generated by the compiler it is equivalent.</p>
<p>I have <a href="https://github.com/jes/scamp-cpu/blob/master/compiler/peepopt">written a simple peephole optimiser</a>, and it reduces runtime of the integration test by nearly 40%, while
also reducing the generated code size by about 20%.</p>
<p>Another weird thing that comes from generating code immediately as the source is parsed is that function declarations appear exactly where they appeared in the source. Imagine some
code like:</p>
<p><pre><code>var f1 = func(x) { return x+1; };
puts("Hello, world!\n");
var f2 = func(x) { return x+2; };</code></pre></p>
<p>The expected result is that <tt>f1</tt> is initialised, and then "Hello, world!" is output, and then <tt>f2</tt> is initialised. But we don't really have a lot of freedom about where the
functions are located in the generated code. My solution is to write each function out exactly where it appears, and a <tt>jmp</tt> instruction beforehand to skip over it.</p>
<p>The SLANG-in-SLANG compiler is generating code that is <i>almost</i> bytewise identical to that produced by the Perl version (in fact, diffing its generated code is
how I verify that it's working correctly!). The only difference is the ordering of the space allocated for globals at the end of the code: the Perl version sorts the globals and the
SLANG version generates them in the order that they appeared in the source.</p>
<p><h3>Writing a compiler as a mind-expanding learning experience</h3></p>
<p>I have really enjoyed working on the compiler. It is the most complicated bit of programming I've done in a while. I've previously been put
off trying to write compilers because I'm obviously not going to do anything better than what's already been done, but the beauty of
compiling a weirdo made-up language for a weirdo made-up CPU is that I'm automatically best-in-class. I'd encourage anyone interested in
programming to dabble in writing a compiler. Part of what made it a good learning experience is that it forced me to concretely
understand a lot of little details, like calling conventions, that I kind-of sort-of thought that I could understand if needed, but rarely had any need
to dig into.</p>
<p><h2>Profiling</h2></p>
<p>At every clock cycle, the emulator increments counters:</p>
<p><ul>
<li>number of cycles spent executing code at the current program counter address</li>
<li>number of cycles spent executing the current opcode</li>
</ul></p>
<p>And at every memory access, the emulator increments a read or write counter for the accessed address. When running with <tt>-p</tt>, the emulator writes this
data out to a file after the program has halted, and <a href="https://github.com/jes/scamp-cpu/blob/master/emulator/profhtml">profhtml</a> turns this into
a slightly-interactive HTML report.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3233"><img src="https://img.incoherency.co.uk/3233/thumb"></a></p>
<p>Looking at a HTML page showing 3 different views of the SCAMP machine's <i>entire address space</i> really highlights just how powerful modern computers are compared
to what SCAMP will be capable of.</p>
<p>I initially wanted to use this data to tell me which functions from the SLANG standard library would be worth hand-optimising in assembly language, but I found that
the visibility it gave me into the machine state actually yielded even more useful results than that, and even more quickly.</p>
<p><h3>1. Quadratic strlen bug</h3></p>
<p>My first results with the SLANG-in-SLANG compiler were showing that at 1 MHz it would take <i>7 minutes</i> just to parse the code for the compiler integration test.
That's before it was even generating code. The profiler showed this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3227"><img src="https://img.incoherency.co.uk/3227/thumb"></a></p>
<p>That's one hell of a hotspot!</p>
<p>I initially thought the profiler was broken. How can it only be executing code at like a dozen addresses? I looked up those addresses in the generated code and it
turned out to be <tt>strlen()</tt>. The compiler was reading the input like this:</p>
<p><pre><code>while (gets(buf+strlen(buf), 16384));</code></pre></p>
<p>i.e. read a line at a time, and append it to the end of <tt>buf</tt>. The problem is that <tt>buf</tt> gets longer each time, and <tt>strlen(buf)</tt> is <i>O(n)</i> in
the length of <tt>buf</tt>. Classic mistake. I actually knew this was bad, but didn't realise just how bad it would be on such a slow machine. More than 5 of the 7 minutes
of execution time would be spent counting the length of the input that it has read so far, just so that it knows where to put the next line of input...</p>
<p><h3>2. Subtle microcode bug</h3></p>
<p>After fixing the quadratic strlen bug, I noticed that the CPU was spending a lot of time executing instruction opcode 0xff. You can see on
the <a href="https://incoherency.co.uk/interest/table.html">instruction set cheatsheet</a> that 0xff is <tt>slownop</tt>. It's an instruction that spends
8 cycles to do nothing. I was surprised that it was spending so much time executing this instruction because the generated code did not include even a single usage of it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3234"><img src="https://img.incoherency.co.uk/3234/thumb"></a></p>
<p>I eventually traced it back to the microcode for the <tt>ld (i16), r</tt> instruction. The microcode for T-state 7 was <tt>YO MI P+</tt>, or in other words,
"put register Y on the bus, load the bus into the current selected memory address, and increment the program counter". But the microinstruction that the emulator was
running was just <tt>YO MI</tt>, without <tt>P+</tt>: it wasn't incrementing the program counter. When the program counter doesn't get incremented to skip over the argument, the argument
gets executed next! That's pretty bad, because the argument could be anything. I shudder to think how I could possibly have debugged this on actual hardware. I
would probably have assumed that my code was doing weird things due to unknowable signal timing problems and left it broken.</p>
<p>So why was it so often 0xff and not just random values? Because the <tt>i16</tt> argument is almost always a pseudoregister, i.e. an address in the top 256 words, i.e. 0xff00 to 0xffff.</p>
<p>Why is the <tt>P+</tt> flag missing from the microcode that is being executed? The <tt>P+</tt> flag occupies the same bit in the microinstruction as one of the ALU control
bits (see the "Decoding" section of the <a href="https://github.com/jes/scamp-cpu/blob/master/doc/UCODE.md">microcode documentation</a>). This means <tt>P+</tt> is only
available when the ALU is not in use, but the <tt>YO</tt> microcode has to use the ALU to load Y onto the bus because the Y register has no mechanism to
do this directly. So <tt>YO P+</tt> is impossible microcode!</p>
<p>Why didn't I notice this sooner? Well I actually did have a check in the microassembler to reject any code that tries to use the ALU and <tt>P+</tt> in the same clock
cycle. The line was:</p>
<p><pre><code>die "P+ with ALU not allowed: $uinstr\n" if $have_alu && $uinstr =~ /\bP\+\b/;</code></pre></p>
<p>Can you spot the problem? It took me a while even when I knew it didn't work!
The problem is that in "YO MI P+", the word boundary is considered to be between the "P" and the "+", not after the "+". So the
regex never matches anything. D'oh!</p>
<p><h3>3. Executing globals</h3></p>
<p>After I fixed the <tt>ld (i16), r</tt> microcode, I still saw a non-zero number of <tt>slownop</tt> executions. The reason for this was much more tame: the compiler puts
globals after the code it generates. The resulting binary is produced by assembling the concatenation of <tt>head.s</tt> which just initialises the stack pointer, then the code generated
by the compiler, and then <tt>foot.s</tt> which halts the emulator and contains some assembly language functions.</p>
<p>The problem is that the compiler doesn't do anything to avoid executing the globals! Once the main program has finished, execution carries on straight through the globals
and does whatever random nonsense is encoded there. I didn't notice this sooner because it normally has no noticeable effect: as long as execution eventually makes it out the other side,
into <tt>foot.s</tt>, the emulator halts and nobody is any the wiser. It doesn't even matter if the "code" in the globals trashed all of the registers and overwrote loads of memory. As
long as the machine promptly halts and nothing appears on the serial console, it appears to be working correctly.</p>
<p><h2>Still to figure out</h2></p>
<p><h3>Slurping the source into memory</h3></p>
<p>The Perl implementation of the compiler slurps the entire source into memory, because that's a fine and reasonable thing to do on a modern computer in 2021. It's unfortunately
not a fine thing to do if you only have 64K of address space. The compiler source totals about 34K bytes, which is too much to be loading into memory, and the
compiler currently runs out of memory trying to compile itself unless you strip whitespace.</p>
<p>I think I plan to use a 256-byte or so <a href="https://en.wikipedia.org/wiki/Circular_buffer">ring buffer</a> to store the input source, and if the parser ever tries
to backtrack further than 256 bytes (i.e. past the oldest data
in the ring buffer), then we'll just bail out and tell the user to make their variable names shorter.</p>
<p><h3>varargs</h3></p>
<p>I don't care about varargs <i>in general</i>, but I really like <tt>printf()</tt>, so I am keen to be able to <i>use</i> varargs functions in SLANG, even if I have to
<i>implement</i> them in assembly language. The problem is that the method of pushing arguments in the order
that they appear in the source means that the first argument to <tt>printf()</tt> (the format string) is the first argument pushed on to the stack, which means it's
the <i>last</i> argument popped off. Normally <tt>printf()</tt> can "safely" work out how many arguments it needs to pop by examining the format string, but that doesn't
work if it needs to know how many arguments to pop in order to work out where the format string is. Potential solutions include:</p>
<p><ol>
<li>pass the format string as the last argument: <tt>printf(1, "jes", "%d. Hello %s\n");</tt></li>
<li>manually pass a final argument saying how many arguments there were: <tt>printf("%d. Hello %s\n", 1, "jes", 3);</tt></li>
<li>have some way to tag functions as "varargs", and push an additional parameter saying how many arguments there were</li>
<li>pass an additional argument saying how many arguments there were to <i>all</i> functions, and just accept the runtime performance hit on every function call</li>
<li>buffer the generated code for each function argument and emit them in reverse order, and just accept the compile-time memory usage hit on every function call</li>
</ol></p>
<p>I don't massively like any of these solutions. Number <b>1</b> is horrible at first glance, but potentially tolerable, and has the benefit of being <i>very</i> easy to implement.
It's likely that I'll accidentally use it wrong sometimes, but it's the kind of bug that is easy to notice and fix. Number <b>2</b> is
asking for trouble, because I can both forget to pass this argument, <i>and</i> pass the wrong number when I don't forget.
Number <b>3</b> would mean variables need some sort of "type" to say whether they point at a varargs function or something else, which I am
opposed to on ideological grounds. Number <b>4</b> might not actually be too crazy, because it also allows for a pleasant fix to the current footgun where passing
the wrong number of arguments to a function breaks everything in confusing ways.
Number <b>5</b> is probably not ideal because compile-time memory usage is at a premium at the moment, but that problem will go away when I stop slurping
the entire source file into memory, so I think it could definitely work.</p>
<p>I think numbers <b>1</b>, <b>4</b>, and <b>5</b> are the likely solutions. I can do number <b>1</b> right now with no compiler changes required (if <tt>printf()</tt> is implemented
in assembly language, so that it can manipulate the stack itself), but maybe the runtime impact of <b>4</b> wouldn't be too bad, I should profile it and find out.
And <b>5</b> probably wouldn't be too hard to do.</p>
<p>If you can think of a better solution than those I listed, or if you have any further arguments for/against any of the options, I'd be interested to hear from you.</p>
<p><h3>Magnitude comparisons</h3></p>
<p>The code generated for magnitude comparisons is still annoyingly broken. This means expressions like <tt>x &lt; y</tt> sometimes evaluate to true even if <tt>x</tt> is
greater than <tt>y</tt>! It compiles into something like "subtract y from x and see if the result is negative". The problem is that integer overflow
means the sign bit can be the opposite of what you want. If I had a carry bit this would be easy to solve, but I threw that away a few weeks ago on the basis that I
couldn't think of a use for it. Hah.</p>
<p>I will probably work on this when I get to writing a program where I care about it, but I expect it might end up a bit hairy.</p>
<p>I also probably want to provide some way to ask for signed vs unsigned magnitude comparison.</p>
<p><h2>Progress on PCBs</h2></p>
<p>My ALU, Memory, and Instruction card PCBs arrived from China today, sooner than expected.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3235"><img src="https://img.incoherency.co.uk/3235/thumb"></a></p>
<p>It would appear that planning to mill the backplane
PCB myself was a bad decision, because so far that project has both taken longer and cost more money than just adding the backplane to the JLCPCB order
would have done. Oh, well. Perhaps foolishly, I still believe that starting from right now, it will cost less money and time to persist in making it myself
than to get the backplane made at JLCPCB.</p>
<p><a href="https://github.com/abetusk/">Abetusk</a> has been a lot of help, in both creating <a href="https://github.com/abetusk/gbr2ngc">gbr2ngc</a>, and advising
me on how to get the most out of it.</p>
<p>Here's a picture of my backplane test piece, held up to the light:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3224"><img src="https://img.incoherency.co.uk/3224/thumb"></a></p>
<p>The tracks are well defined, although extremely thin: about 0.3 mm across. The full PCB layout is this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3191"><img src="https://img.incoherency.co.uk/3191/thumb"></a></p>
<p>I thought the test piece looked like it was going to work, so I then moved on to trying to make the actual backplane,
but then I broke my only good engraving tool, and the "bad" engraving tools cut a line that is too wide, because the tip is not concentric with the shaft:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3226"><img src="https://img.incoherency.co.uk/3226/thumb"></a></p>
<p>I am going to try again with a couple of different types of tools, but might give up and get it from JLCPCB instead.</p>
<p>Abetusk recommended using 25&deg; tools instead of 10&deg; because they are more robust,
but the wider angle comes with more sensitivity to height variation. I have also acquired a 0.2 mm end mill, although I don't have high hopes for its robustness.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3231"><img src="https://img.incoherency.co.uk/3231/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/slang.html</link>
   <guid>http://incoherency.co.uk/blog/stories/slang.html</guid>
   <pubDate>Fri, 19 Feb 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to use an AT28C16 EEPROM with an Arduino Uno without a port expander</title>
   <description><![CDATA[The AT28C16 EEPROM stores 2048 bytes, which means to access it all you need to control 11 address lines and 8 data lines. You also need to operate
"chip enable" (pull low to enable the AT28C16), "output enable" (pull low to enable output), and "write enable" (pull low to enable
writing). That means in total you need to control 22 pins, but the Arduino Uno only has 12 general-purpose digital IO pins. Problem. Fortunately,
there are some tricks that make it workable.]]></description>
   <content:encoded><![CDATA[<p>The AT28C16 EEPROM stores 2048 bytes, which means to access it all you need to control 11 address lines and 8 data lines. You also need to operate
"chip enable" (pull low to enable the AT28C16), "output enable" (pull low to enable output), and "write enable" (pull low to enable
writing). That means in total you need to control 22 pins, but the Arduino Uno only has 12 general-purpose digital IO pins. Problem. Fortunately,
there are some tricks that make it workable.</p>
<p>I built my EEPROM programmer with a ZIF socket on <a href="https://incoherency.co.uk/blog/stories/pcb-milling-2.html">a homemade PCB</a>, but you can do it on a breadboard. You won't
need any external components: just the Arduino Uno, EEPROM, a breadboard, and some wires.</p>
<p>Here's the pinout of the AT28C16:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3225"><img src="https://img.incoherency.co.uk/3225/thumb"></a></p>
<p>And <a href="https://incoherency.co.uk/interest/at28c16.pdf">here's a link to the datasheet</a>.</p>
<p>The first AT28C16's I tried did not work, I believe they are either broken or fake. I subsequently purchased one from <a href="https://www.ebay.co.uk/usr/themicrohut">themicrohut</a>
and it was packaged well, arrived promptly, and worked. I recommend <b>themicrohut</b> and do not recommend "bigvip8018".</p>
<p><h2>Permanently enable the EEPROM</h2></p>
<p>If we don't actually need to <i>control</i> "chip enable" (say, if the only purpose of our project is to interact with the EEPROM), then we can tie
"chip enable" directly to ground and save 1 pin.</p>
<p><h2>Analogue pins</h2></p>
<p>The Arduino Uno has 6 analogue pins, but these can also be used as digital pins.</p>
<p><h2>Use the serial port for GPIO</h2></p>
<p>Arduino pins 0 and 1 are used for serial communication with the PC over the USB cable. Ordinarily you have to decide whether you want to use
USB serial (in which case call <tt>Serial.begin()</tt>), or you want to use pins 0 and 1 for something else (in which case don't call <tt>Serial.begin()</tt>).
But we can actually <i>almost</i> get to have our cake and eat it by turning serial off while interacting with the EEPROM.</p>
<p>If you make sure that pins 0 and 1 are not connected to "output enable" or (most importantly) "write enable", then communication over the serial
line will have no effect on the EEPROM. Just call <tt>Serial.end()</tt> before trying to use those pins, and then <tt>Serial.begin()</tt> again
to go back to using the serial port.</p>
<p>You need to coordinate this with whatever is on the PC side of the serial connection. I haven't tested extensively, but it seems as if the PC side
gets end-of-file on the serial device if it tries to read while the Arduino has turned serial off. It also seems that the PC side reads a nul byte
immediately after the Arduino turns the serial back on. I "solved" these problems on the PC side as follows:</p>
<p><ul>
<li>after sending a command, sleep for long enough for the Arduino to handle it before trying to read the response</li>
<li>strip nul bytes from responses</li>
</ul></p>
<p><h2>Control an address line by hand</h2></p>
<p>So now we actually are using <i>all</i> of the pins that the Arduino Uno can control, and we're still 1 pin short of being able to use the
AT28C16.</p>
<p>My solution for the last pin was to put a manual jumper on the high address bit, and have the human switch it. When the jumper is closed A10
is tied to ground (logic 0), and when the jumper is open the pull-up resistor pulls it to 5v (logic 1).
When reading/writing the EEPROM,
the software on the PC side acts on the first half of the address space, then asks the human to switch the high address bit, and then acts on the second half.</p>
<p>If you wanted it to be a bit more convenient you could use a switch instead of a jumper.</p>
<p><h2>Source code</h2></p>
<p>You can get <a href="https://github.com/jes/scamp-cpu/blob/master/arduino/eeprom-burner/eeprom-burner.ino">the Arduino program</a>,
and the <a href="https://github.com/jes/scamp-cpu/blob/master/util/dump-eeprom">dump-eeprom</a> and <a href="https://github.com/jes/scamp-cpu/blob/master/util/burn-eeprom">burn-eeprom</a>
programs on my <a href="https://github.com/jes/scamp-cpu/">SCAMP github project</a>.</p>
<p>Currently it only supports reading or writing 1 byte at a time, but since I ~always want to read/write the entire EEPROM, it would probably
be worth adding a way to batch up 1024 bytes at a time in between toggling the serial port on and off, just to speed things up. The Arduino only has
2048 bytes of RAM, but I'm not using half of it yet, so I am pretty sure a 1024-byte buffer would be fine. If not, even a 512 or 256 byte buffer would be
an improvement over just 1 byte at a time.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/arduino-at28c16-without-port-expander.html</link>
   <guid>http://incoherency.co.uk/blog/stories/arduino-at28c16-without-port-expander.html</guid>
   <pubDate>Wed, 17 Feb 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>My second attempt at milling a PCB</title>
   <description><![CDATA[The day after my first attempt at milling a PCB, my new tooling
arrived (a 1 mm drill bit and a 10&deg; engraving tool), so I had another go at making a PCB.]]></description>
   <content:encoded><![CDATA[<p>The day after <a href="https://incoherency.co.uk/blog/stories/pcb-milling.html">my first attempt at milling a PCB</a>, my new tooling
arrived (a 1 mm drill bit and a 10&deg; engraving tool), so I had another go at making a PCB.</p>
<p>Here's what I made:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3218"><img src="https://img.incoherency.co.uk/3218/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3219"><img src="https://img.incoherency.co.uk/3219/thumb"></a></p>
<p>(<a href="https://img.incoherency.co.uk/group/44.html">More pictures of the process available</a>.)</p>
<p>And here's a video of it all:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/Yb1cjJme_r4" frameborder="0" allowfullscreen></iframe></p>
<p>The big problem last time was that the cut depth was too inconsistent, and my plans for fixing that were to
re-surface the wasteboard so that the PCB is more square to the machine, and to use mesh leveling to counteract
any remaining unevenness.</p>
<p>I re-surfaced a portion of the wasteboard but didn't bother with mesh leveling, and this turned out to be good enough. Great success.</p>
<p><h2>Isolation routing</h2></p>
<p>After the isolation routing, the board looked like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3210"><img src="https://img.incoherency.co.uk/3210/thumb"></a></p>
<p>You might be able to see that the routed traces have quite a rough edge. Maybe this would be improved by cutting more slowly. I fixed it by
sanding with some quite fine sandpaper:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3212"><img src="https://img.incoherency.co.uk/3212/thumb"></a></p>
<p>This might have left some copper dust in the gaps between the traces. I'm not sure if there's a better option here. I cleaned up the gaps
by running a sharp knife through them to extract the dust.</p>
<p><h2>Silkscreen</h2></p>
<p>I did the silkscreen by first spraying the non-coppered side of the board black, and then engraving the silkscreen
layer into it. This worked really well, I would do this again.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3214"><img src="https://img.incoherency.co.uk/3214/thumb"></a></p>
<p><h2>Edge cuts</h2></p>
<p>I made a bit of a mess of the edge cuts:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3221"><img src="https://img.incoherency.co.uk/3221/thumb"></a></p>
<p>There was a lot of tearing and burning as it was cutting.</p>
<p>I initially thought that this was caused by running the cut too fast for the 2 mm end mill, but I subsequently discovered that the collet was loose!
I'm surprised it managed to cut at all and didn't just break the end mill.</p>
<p>I cleaned up the edges of the board with a file, and tried to clean the mess off the paint with soap and water, but it was to little avail. Next time I should tighten
the collet instead.</p>
<p><h2>Soldering</h2></p>
<p>The soldering was very tricky, due to the lack of soldermask.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3218"><img src="https://img.incoherency.co.uk/3218/thumb"></a></p>
<p>There is only a <i>very</i> small amount of clearance between the pads and the rest of the board. I managed
to create a couple of solder bridges, which were tricky to clean up.</p>
<p>Re-melting the solder that has jumped the gap is not a successful strategy, because the more you heat it up, the more it wants to flow onto the
copper. I eventually found that cutting through it with a sharp knife works better.</p>
<p>See the pin nearest to the camera:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3222"><img src="https://img.incoherency.co.uk/3222/thumb"></a></p>
<p>Another issue is that because there is only copper on the bottom side of the board, and I want the pins to stick out the bottom,
I couldn't solder the pin header on "correctly". I bodged this by sliding the plastic clip right to the end of the pins, putting the clip on
the top side, and soldering the pins on the copper side. It does the job, and I can't really think of a better solution on a single-sided board.</p>
<p><h2>Writing to an EEPROM</h2></p>
<p>So far I think the homemade PCB is a great success. Apart from the burnt edges it is all very high quality, much better than I expected.</p>
<p>Now there's just the small matter of actually <i>using</i> the EEPROM burner.</p>
<p>To cut a long story short, I couldn't get it to work.</p>
<p>I have tentatively concluded that the EEPROM chips I've bought just don't work. I couldn't get them to do anything at all. To rule out my homebrew PCB,
I plugged an EEPROM chip into a breadboard, applied power, enabled "chip enable" and "output enable" by tying them to ground, disabled "write enable"
by tying it to 5 volts, and found that all of
the output pins were still floating. The relevant section from the datasheet is:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3223"><img src="https://img.incoherency.co.uk/3223/thumb"></a></p>
<p>Which seems pretty unequivocal. Even though I left the address lines floating, there should be at least <i>some</i> value asserted on the outputs, but there
is nothing. Frustrating. I don't know if the chips are real AT28C16's that are just broken, or if they're some random other less valuable chips that have been rebadged
and flogged off on eBay. Either way they're not much use to me.</p>
<p>The chips were packaged extremely poorly when they were sent to me:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3170"><img src="https://img.incoherency.co.uk/3170/thumb"></a></p>
<p>I wonder if this is because the seller knew they didn't work and therefore didn't want to waste any money on unnecessary packaging materials.</p>
<p>I initially bought 2 packages of 2 chips each from this seller, because I need 4 in total, and they arrived on separate days. After the first package arrived, I messaged
the seller to complain about the quality of the packaging, and was told that this isn't intended and must be a one-off mistake. When the second package arrived,
it was packaged identically to the first, and also had bent pins. I left negative feedback and moved on, but even at that point
I didn't expect that the chips just <i>wouldn't work</i>!</p>
<p>Fool me once, shame on you. You can't get fooled again. So I have this time ordered only a <i>single</i> AT28C16, from a different seller, and look forward to testing it.</p>
<p><h2>Backplane</h2></p>
<p>Since making the EEPROM burner, I had a first attempt at making the backplane for <a href="https://github.com/jes/scamp-cpu">SCAMP</a>, but I chipped the end
off the engraving tool by running the cut too fast (due to a software bug).
I have some more engraving
tools on the way, and will hopefully blog about my completed backplane soon.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/pcb-milling-2.html</link>
   <guid>http://incoherency.co.uk/blog/stories/pcb-milling-2.html</guid>
   <pubDate>Mon, 15 Feb 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>My first attempt at milling a PCB</title>
   <description><![CDATA[I'm going to get most of the PCBs for SCAMP made by JLCPCB, but I'd like
to try to mill the backplane on the CNC machine because it is both large (expensive at
JLCPCB) and simple (single-sided, no vias, easy to make). Yesterday some small pieces of copper-clad
board arrived and today I had a first attempt to see what would go wrong.]]></description>
   <content:encoded><![CDATA[<p>I'm going to get most of the PCBs for <a href="https://incoherency.co.uk/blog/tags/cpu.html">SCAMP</a> made by JLCPCB, but I'd like
to try to mill the backplane on the CNC machine because it is both large (expensive at
JLCPCB) and simple (single-sided, no vias, easy to make). Yesterday some small pieces of copper-clad
board arrived and today I had a first attempt to see what would go wrong.</p>
<p>This is what I got:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3194"><img src="https://img.incoherency.co.uk/3194/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3195"><img src="https://img.incoherency.co.uk/3195/thumb"></a></p>
<p>It's meant to be an EEPROM burner (how did you guess?), but obviously this one is not going to work. It doesn't look far off
though, I think the PCB milling process is going to work.</p>
<p><h2>Principle</h2></p>
<p>Start with a copper-clad <a href="https://en.wikipedia.org/wiki/FR-4">FR-4</a> board. This is a fibreglass board with a thin
layer of copper on one side. This is the normal type of board that a single-sided PCB is made from. Double-sided PCBs use the
same stuff, but with copper on both sides.</p>
<p>Using a very fine cutting tool, cut out the copper around the edges of
the areas that you want to conduct, so that the conductors are isolated from one another, also
called "isolation routing" or "isolation milling". You're left with a board that is functionally equivalent to an etched PCB,
but for a fraction of the effort.</p>
<p>In theory you <i>can</i> do double-sided boards if you're careful about alignment when flipping the board over, but you don't get plated-through-holes,
which means you need to be cognizant of which side components are soldered to (because they won't be connected to the other side),
and you need to manually put a bit of wire or something inside vias, and unless you can use a <i>very</i> small drill bit, your vias have to be quite a bit bigger
than normal.</p>
<p>For my case, on single-sided boards, the main downsides compared to a professionally-manufactured PCB are that trace width and clearance
need to be larger, and there's no solder mask and no silkscreen. The benefits are the quicker turnaround time compared to waiting for a board to
be shipped from China, and the obvious cost saving.</p>
<p><h2>PCB design</h2></p>
<p>The EEPROM burner design looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3196"><img src="https://img.incoherency.co.uk/3196/thumb"></a></p>
<p>It's meant to sit on top of an Arduino Uno and hold a ZIF socket so that I can program the
EEPROMs. Unfortunately the Uno is 1 GPIO pin short of what I needed, so there is a jumper that allows
me to manually select the high address bit. That's annoying but I don't plan to have to use it
very often. A better solution would be to use something like an <a href="https://www.circuitbasics.com/how-to-use-an-mpc23017-port-expander-on-the-arduino/">MCP23017
port expander</a> to let the Arduino drive more pins than it physically has.</p>
<p>I didn't make a schematic for the board, I manually laid it out directly in <a href="https://docs.kicad.org/5.1/en/pcbnew/pcbnew.html">Pcbnew</a>.</p>
<p>The backplane PCB layout is only slightly more difficult, mainly because it needs to route traces in between pads, which means the traces need to be narrower
and closer together:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3191"><img src="https://img.incoherency.co.uk/3191/thumb"></a></p>
<p><h2>gbr2ngc</h2></p>
<p>I tried using <a href="https://github.com/pcb2gcode/pcb2gcode">pcb2gcode</a> and <a href="http://flatcam.org/">FlatCAM</a>, but couldn't get either
of them to build and run successfully.</p>
<p>I then found <a href="https://github.com/abetusk/gbr2ngc">gbr2ngc</a>, "Open source no frills Gerber to gcode converter", which does precisely what I
wanted and no more, and it builds and runs easily. Great success.</p>
<p>I did find that since I wanted copper on the bottom of the board instead of the top, it generated the G-code as if it was looking directly through the PCB, and I needed
to invert the Y coordinates separately. I added a <tt>--invert-y</tt> option to <a href="https://github.com/jes/gcodetile/">gcodetile</a>
to do this for me, and strung everything together with a little <a href="https://github.com/jes/scamp-cpu/blob/master/kicad/eeprom-burner/gerber/mk-gcode">shell script</a>.</p>
<p>The G-code paths for the copper cuts look like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3198"><img src="https://img.incoherency.co.uk/3198/thumb"></a></p>
<p><h2>drl2gcode</h2></p>
<p>Converting Gerbers to G-code is only half the story: we also want to automate the hole drilling.</p>
<p>I found <a href="https://git.nexlab.net/machinery/drl2gcode">drl2gcode</a> on <a href="https://www.nexlab.net/">nexlab</a>'s gitlab
instance. It does almost exactly what I want, but it generated G-code that wasn't quite right for my machine, and took configuration
parameters as globals instead of command-line options, so I made <a href="https://github.com/jes/drl2gcode">some changes</a> that were more to my taste.</p>
<p><h2>argparse</h2></p>
<p>Incidentally, I found the Python <a href="https://docs.python.org/3/library/argparse.html">argparse</a> documentation to be surprisingly obtuse. It includes
a confusing example of a command-line switch that changes a parameter from pointing at the <tt>max()</tt> function to make it point at the <tt>sum()</tt>
function, but it does not include an example of how to take a named numeric argument, like <tt>--spindle-speed 10000</tt>. I just guessed a few variations
until it worked.</p>
<p>Here's the Python <tt>argparse</tt> example usage:</p>
<p><pre><code>import argparse</p>
<p>parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
                    help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
                    const=sum, default=max,
                    help='sum the integers (default: find the max)')</p>
<p>args = parser.parse_args()
print(args.accumulate(args.integers))</code></pre></p>
<p>And here's the Perl <tt>Getopt::Long</tt> example usage:</p>
<p><pre><code>use Getopt::Long;
my $data   = "file.dat";
my $length = 24;
my $verbose;
GetOptions ("length=i" => \$length,    # numeric
            "file=s"   => \$data,      # string
            "verbose"  => \$verbose)   # flag
or die("Error in command line arguments\n");</code></pre></p>
<p>Maybe I'm biased, but I know which one makes more sense to me.</p>
<p><h2>Cutting copper</h2></p>
<p>Having generated my G-code, I went out to the garage armed with a USB stick, a copper-clad board, and a cup of tea.
I arrived to find the room at 0&deg;C, which is less than I prefer.</p>
<p>I stuck the copper-clad board to the bed with double-sided tape. I'm not sure if this would be enough to hold it for the edge cuts,
but it's more than adequate for the isolation routing.</p>
<p>Here's the picture of the board again:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3194"><img src="https://img.incoherency.co.uk/3194/thumb"></a></p>
<p>The problem here is that the top surface of the copper was not perpendicular to the Z axis of the machine, which
means the cuts are too deep in some areas and not deep enough in others. Here's an exaggerated example of a constant cut depth against a part
that is not perpendicular to Z:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3206"><img src="https://img.incoherency.co.uk/3206/thumb"></a></p>
<p><h3>Tool geometry</h3></p>
<p>But we actually only really care about cut <i>width</i>, not <i>depth</i>. As long as we are cutting the copper away, and not cutting all the way out
the other side of the board, we only care about cut depth to the extent that the cut width
varies with depth. We can mitigate this problem by using a steeper tool:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3205"><img src="https://img.incoherency.co.uk/3205/thumb"></a></p>
<p>The steeper tool causes less width variation as the cutting depth varies. The ideal case would be an extremely thin tool with straight sides (i.e.
an extremely narrow end mill), but I think a ~0.1 mm end mill would be too fragile.</p>
<p>I am still awaiting delivery of a 10&deg; engraving tool, so today I used a small 60&deg; engraving tool that I already had.</p>
<p><h3>Bed surfacing</h3></p>
<p>I use an MDF wasteboard on my bed, and part of the reason that the cut depth is not uniform is because my wasteboard
has been cut up a bit, which means the surface of the wasteboard is no longer flat. I would probably get a substantial
improvement from re-surfacing it, which just involves running a large cutter back and forth over the entire surface at a
fixed height.</p>
<p><h3>Mesh leveling</h3></p>
<p>A more general solution is to probe the height across the entire board before we start milling, and then offset the Z coordinate at
each point by the probed Z coordinate from the bed:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3203"><img src="https://img.incoherency.co.uk/3203/thumb"></a><br>
<small>(Thumbnail from <a href="https://www.youtube.com/watch?v=6WNE3E1ZZYY">this video</a>.)</small></p>
<p><a href="https://winder.github.io/ugs_website/guide/platform/">UGS Platform</a> includes a plugin to do this, but I loaded it up and it
popped up a box saying that it doesn't work correctly, so I didn't risk it. I will probably try out the plugin at some point, but failing
that, it would not be too hard to write a program to do mesh leveling myself:</p>
<p><ol>
<li>probe the Z height in a grid that covers the part</li>
<li>export the measured Z heights in a text file</li>
<li>read in the G-code for the part and adjust each Z coordinate by the corresponding (interpolated) Z height from the probe data</li>
</ol></p>
<p><h2>Cutting silskcreen</h2></p>
<p>Silkscreen is not really important for the EEPROM burner, but I'm keen to be able to put writing on the backplane so that I can label the signals,
so I thought I'd test it out on the EEPROM burner.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3195"><img src="https://img.incoherency.co.uk/3195/thumb"></a></p>
<p>There are a few things here.</p>
<p>Firstly the horrible sticky residue is from the double-sided tape that I used to stick the board down when cutting the copper side. Normally
the tape peels off easily without any residue left behind, but I think it doesn't like the cold. Hopefully it will be warmer next time, if not
I might heat the board up before peeling the tape off. If that doesn't help, then it might be that the tape sticks to FR-4 much better than
it sticks to aluminium, and I'll have to think of something else. Maybe just dissolve it with isopropyl alcohol.</p>
<p>The second thing is that the cuts are very deep. They are much deeper than necessary, because the cut depth is not really critical and I couldn't
be bothered trying to set it up precisely, but it makes the small text quite hard to read, so next time I'll try to do better.</p>
<p>The third thing (masked by the excessive cut depth) is that <tt>gbr2ngc</tt> has actually tried to isolation-route this layer, i.e. it has tried to cut around
the outside of the letters, instead of cutting the letters directly. That's not a big problem, and I don't think I'll try to fix it.</p>
<p>To make the writing stand out a bit, I traced over the cuts with a Sharpie and then tried to rub off the excess. It mostly worked, and I might stick
with this method, mainly the sticky residue made it hard to rub off the excess. Another idea I've had is to spraypaint the board black <i>before</i> making
the cuts, so then the cuts will be fibreglass-coloured and the rest of the board will be black. Might be less work because I don't need to manually go over
every cut, and I don't need to rub off the excess.</p>
<p>The small writing is kind of hard to read, but I expect this will be improved by using a steeper cutting tool and setting the depth more precisely.</p>
<p>The path I used looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3201"><img src="https://img.incoherency.co.uk/3201/thumb"></a></p>
<p>If you zoom in you'll see that each line is actually 2 lines spaced very slightly apart.</p>
<p><h2>Drilling</h2></p>
<p>I didn't run the G-code for drilling the holes because my 1 mm drill bit has not arrived yet, and I didn't see that it would be much use
drilling it a different size since the PCB obviously isn't going to work anyway. The path looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3199"><img src="https://img.incoherency.co.uk/3199/thumb"></a></p>
<p>For next time I will invert the Y coordinate of the drilling path so that it can be done while the board is still upside down, that way if there's any
misalignment when the board is flipped over for the silkscreen, at least the holes will still be in the right place.</p>
<p><h2>Edge cuts</h2></p>
<p>I also didn't run the G-code for making the edge cuts, although in hindsight I should have done, to find out whether the sticky tape would be sufficient
to hold the PCB. The path looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3200"><img src="https://img.incoherency.co.uk/3200/thumb"></a></p>
<p><tt>grb2ngc</tt> initially generated a path like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3202"><img src="https://img.incoherency.co.uk/3202/thumb"></a></p>
<p>Because it views the "edge cuts" as if they are copper traces that want to be isolation routed. The generated G-code is neatly labelled in
2 paths, though, so it's easy to get rid of the second one with <tt>sed</tt>.</p>
<p><h2>Next attempt</h2></p>
<p>I plan to:</p>
<p><ul>
<li>use a 10&deg; cutting tool instead of 60&deg;</li>
<li>re-surface the wasteboard</li>
<li>work out how to do mesh leveling</li>
<li>use a more precise cut depth on silkscreen</li>
<li>invert Y coordinate for drill G-code</li>
<li>try out the drill and edge cut G-code</li>
<li>heat the board up before peeling the tape off if it's cold</li>
</ul></p>
<p>And hopefully that will be enough to get a working PCB.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/pcb-milling.html</link>
   <guid>http://incoherency.co.uk/blog/stories/pcb-milling.html</guid>
   <pubDate>Fri, 12 Feb 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Making a start on the SCAMP ALU cards</title>
   <description><![CDATA[I'm pretty happy with the CPU design now and am ready to proceed to making it physically exist. I
am still finding the odd microcode bug, but these can be fixed at any time. I'm at least not finding any
architecture-level bugs.]]></description>
   <content:encoded><![CDATA[<p>I'm pretty happy with the CPU design now and am ready to proceed to making it physically exist. I
am still finding the odd microcode bug, but these can be fixed at any time. I'm at least not finding any
architecture-level bugs.</p>
<p><h2>Physical organisation</h2></p>
<p>I think I want a metal box with a backplane at the back, and cards that slide in from the front. One of the mistakes I made with
my RC2014 build is that I put all the electronics inside a metal box with no way to access them without opening the case. This
makes hardware modification dramatically less convenient than if you just have the RC2014 cards directly accessible.
So for SCAMP I definitely want to be able to slide the cards in and out without tools.</p>
<p>I was also thinking that I might implement the "front panel" as 3d-printed mini-front-panels directly on the cards.
For example, the card that holds the instruction
register would have LEDs at the front that indicate the contents of the instruction register, rather than having wires running
to LEDs on a separate panel.</p>
<p>And I think I've had quite enough of manually entering code <a href="https://incoherency.co.uk/blog/stories/rc2014-frontpanel.html">using switches on the front panel</a>,
so I don't think I need to support that. All I really want from the front panel is single-stepping, clock speed control, and blinkenlights.</p>
<p>I considered using card-edge connectors to connect the cards to the backplane, but I've never used them before, and it seems like
it would be easy for me to accidentally get the PCBs made in the wrong thickness, or with the wrong plating, or something else,
and then they wouldn't connect properly. I thought it more prudent to just go for pin headers for the backplane connection.</p>
<p>By the way, if you are trying to buy female pin headers on Farnell, then you need to look in the "PCB Receptacles"
category.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3176"><img src="https://img.incoherency.co.uk/3176/thumb"></a></p>
<p>I'm planning to use 2x30 pin headers, with male headers on the backplane and female right-angle "receptacles" on the cards. I
thought it best to put the male side on the backplane, because pins are more easily damaged than sockets, and it is likely
that they'll be better-protected inside the chassis than loose on the cards. I'm thinking I'll have some guide rails in the
sides of the chassis that guide the receptacles directly onto the pins, to avoid misalignment.</p>
<p>I haven't completely decided how I'll arrange the logical modules of the CPU into cards, but it'll be something like:</p>
<p><table border>
<tr><th>Card</th><th>Modules</th><th>Chips</th></tr>
<tr><td>ALU</td><td>ALU, X register, Y register, flags register</td><td>43</td></tr>
<tr><td>Memory</td><td>ROM, RAM, address register</td><td>9</td></tr>
<tr><td>Instruction</td><td>Instruction register, microcode ROM, control logic, sequencer, program counter</td><td>22</td></tr>
<tr><td>I/O</td><td>UART, CompactFlash, SD card</td><td>?</td></tr>
<tr><td>Clock</td><td>Clock circuit, single-stepping, reset button, power switch</td><td>?</td></tr>
</table></p>
<p><h2>ALU cards</h2></p>
<p><h3>Concept</h3></p>
<p>I'm starting with the electronics for the ALU because it will be the most complicated. I'll then know that whatever PCB size I
end up with, as long as I can fit the ALU on it, I should be able to fit the others in the same amount of space.</p>
<p>In the TTL-Verilog implementation, I split up the function of the ALU into <a href="https://github.com/jes/scamp-cpu/blob/master/ttl-alu4.v">4-bit
slices</a>, and then used 4 copies of this to build the 16-bit ALU. Similarly, the X and Y register are each naturally implemented with 2x 8-bit-wide
74377 register chips.</p>
<p>It is therefore natural to split the ALU into 2 physical cards. One card would implement the low 8 bits and the other would do the high 8 bits.
We don't even need to transfer bus or register contents between the 2 cards. Each card already has its own connection to the bus, and takes its control
signals from the bus, and neither
card needs access to the register bits that are stored on the other card.
We just need a flying jumper between the cards to pass the carry bit up. The minimum order from JLCPCB is 5 boards, so needing to buy 2 copies of
the card doesn't even cost any more money, and in fact saves money because the resulting PCBs are smaller.</p>
<p>We also need the flags register to be implemented on the ALU cards. It is sufficient to leave the footprint for the flags register on both cards
and only populate it on one. Part of the flags register calculation is checking whether the ALU output is 0, so we need a second flying
jumper to pass the "zeroness" check of the secondary card up to the primary card.</p>
<p>Finally, to connect up the 2 cards to the upper or lower bits of the bus, I'm using solder jumpers. On one card the 8 solder jumpers would be
connected to bus[0]..bus[7], on the other card they'd be connected to bus[8]..bus[15].</p>
<p>In terms of physical packaging, I'm planning to screw the 2 cards together using a standoff which spaces them apart to match the connector spacing
on the backplane. They'd use a shared 3d-printed front panel piece, which would present convenient views of the X and Y register, flags register,
ALU operation selection, and ALU output. Something like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3177"><img src="https://img.incoherency.co.uk/3177/thumb"></a></p>
<p>Not my proudest sketch, but it perhaps communicates the idea. The front panel is a 3d print that houses the LEDs. The LEDs are plugged into pin headers
directly on the cards (with 8 bits of X,Y from the top card and the other 8 bits from the bottom card). Then the cards are each populated with the
chips required to implement their logic, with a couple of flying jumpers to pass extra bits between them, standoffs to hold them together, and a
backplane connector at the back of each card.</p>
<p><h3>Implementation</h3></p>
<p>I have made a start on the PCB design, but there is still some stuff I want to change. Here's what I have so far:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3174"><img src="https://img.incoherency.co.uk/3174/thumb"></a></p>
<p>(Just to keep you on your toes, this picture has the backplane connector on the left instead of the right, compared to the sketch).</p>
<p>This time I made a point of routing horizontal traces on one side of the card and vertical traces on the other. I think I got the
idea from an <a href="https://www.youtube.com/user/EEVblog">EEVBlog</a> video, but I don't remember which one. It is a great idea
because it makes it a <i>lot</i> easier to route the last traces if you can always predict where you're able to go without crashing
into things. I still used KiCad's push-and-shove router, which is clearly the best way to route traces and I don't know why it is not
the default.</p>
<p>I did notice one issue with the push-and-shove router: sometimes, if you're routing a long trace, you can get it to a point where you
want to drop a via, hold the mouse still, and press "V" to drop the via, but as soon as you press "V" it looses its route and you have to
start again. I don't know why. The trick is to click just before you drop the via to lock in the route you have so far so that it can't go anywhere.</p>
<p>The PCB is about 103 mm tall and 237 mm wide. It could clearly be smaller, but I don't know if it's worth starting again to make it smaller.</p>
<p><h2>Other</h2></p>
<p><h3>EEPROM</h3></p>
<p>The logic chips are mostly going to be fitted in normal DIP sockets, but for the boot ROM and microcode ROM, I'm going to be using
<a href="https://en.wikipedia.org/wiki/Zero_insertion_force">Zero-insertion force</a> ("ZIF") sockets, to avoid bending the pins.</p>
<p>I bought 4x Atmel AT28C16 EEPROMs from eBay. They arrived packaged like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3170"><img src="https://img.incoherency.co.uk/3170/thumb"></a></p>
<p>So much for not bending the pins...</p>
<p>I have manually straightened out the pins and miraculously none of them have broken off, but I'm not sure how many insertions I can expect
before they fail. The pins are also very corroded, as if they have been stored outdoors for several months, despite being sold as "New".</p>
<p><a class="img" href="https://img.incoherency.co.uk/3178"><img src="https://img.incoherency.co.uk/3178/thumb"></a></p>
<p>I still need to make an Arduino-based EEPROM programmer, but I don't expect that will be difficult.</p>
<p>The AT28C16 chips each store 2 KBytes of data. For the boot ROM I only need 256 Bytes from each one, but I couldn't find any convenient smaller EEPROMs
and these weren't too expensive, so I don't mind wasting the rest.</p>
<p><h3>RAM</h3></p>
<p>For RAM I'm going to be using 2x Winbond W24512A chips. These are each 64 KBytes of RAM, together providing 64 KWords. The lower 256 words
will not be accessible because the EEPROM will be mapped there. But again I don't mind wasting this space.</p>
<p>The RAM chips were packaged much better than the EEPROMs:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3180"><img src="https://img.incoherency.co.uk/3180/thumb"></a></p>
<p><h3>UART</h3></p>
<p>I wanted to use a <a href="https://en.wikipedia.org/wiki/MOS_Technology_6551">MOS 6551</a> for the serial port, because (almost uniquely, it
seems) it has an onboard clock source to provide the baud rate.</p>
<p>One of the things I don't like about the RC2014 is that the baud rate of the serial ports is derived from the CPU clock, which means if you
use a slow clock, your serial terminal doesn't work properly. I'm keen to avoid this.</p>
<p>Unfortunately the 6551 is pretty hard to find, and I couldn't find any available on Farnell, RS Components, or eBay. So that rules that out.</p>
<p>The next best option that I could find is the <a href="https://en.wikipedia.org/wiki/8250_UART">National Semiconductor 8250</a> (now cloned by
lots of other companies). This is the chip used in the original IBM PC to provide the serial ports. It requires an external clock source, which
is potentially annoying, but does at least have quite a wide-ranging internal divider to allow different baud rate selection in software.</p>
<p>It is quite a big chip, here it is next to the EEPROM, which is itself not small:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3181"><img src="https://img.incoherency.co.uk/3181/thumb"></a></p>
<p>I have only bought one so far. I definitely want one to use for the console, and probably once I am satisfied that it is going to do what I want I
will buy a second one to use for <a href="https://incoherency.co.uk/blog/stories/rc2014-web-server.html">SLIP networking</a> or talking to Arduinos.</p>
<p>To implement the serial console, I probably want to get something like <a href="https://www.tindie.com/products/petrohi/geoffs-vt100-terminal-kit/">Geoff's
VT100 Terminal Kit</a>.</p>
<p><h2>Storage</h2></p>
<p>I am not yet sure what I'm going to be doing for storage. The obvious candidates are to use a CompactFlash card or an SD card. I think using an SD card
in SPI mode would be an unnecessary performance bottleneck (especially if I want to support a "process stack" <tt>system()</tt> implementation that swaps
the running process out to disk to execute a child process). But I understand that the easiest way to use a CompactFlash card is in IDE mode, and if I'm
going to be supporting IDE then it's cooler to buy an old hard disk and use that instead.</p>
<p>But supporting an SD card as secondary storage might be useful for exchanging files with other computers. I'd really like to be able to do this year's
<a href="https://incoherency.co.uk/blog/stories/advent-of-code-2020.html">Advent of Code</a> on SCAMP, and an SD card would be a convenient way to get problem inputs onto the computer,
and finished programs off.</p>
<p><h2>FPGA CPU</h2></p>
<p>I've now got an FPGA implementation of the CPU. I initially thought this would be relatively trivial, but it turns out that FPGAs don't really like
tri-state logic. My solution was to replace all of the tri-state bus-driving logic with a single big mux that sets the bus contents based on whatever
should be driving it. The FPGA I have also doesn't have enough space to store 64 KWords of RAM, so a lot of the RAM is just a black hole in the FPGA
version.</p>
<p>But it <i>does</i> work, and I have been able to write <a href="https://github.com/jes/scamp-cpu/blob/master/bootrom-fpga.s">a program</a> that tests
the state of the buttons on the evaluation board, and mirrors this over to the LED array. I accept that it would probably be less code if it was written directly
in Verilog, but it serves its purpose as a CPU test.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3185"><img src="https://img.incoherency.co.uk/3185/thumb"></a></p>
<p>I exposed the buttons as input device 0 (so when you ask for input from device 0, the lower 4 bits are set or not based on whether the corresponding button
is pressed or not), and the LEDs as 4 output devices (the lower 8 bits of the data written to device 0 goes to the first row of LEDs, etc.).</p>
<p>My initial motivation for the FPGA implementation was that it would allow me to test external hardware "piecemeal", by just deleting the corresponding Verilog and
connecting its inputs/outputs to some physical pins. Unfortunately I now realise that won't work, because the CPU I'm making is all going to run on 5v logic,
and the FPGA only supports 3.3v. Never mind.</p>
<p><h2>Oscillocopes, logic analysers</h2></p>
<p>I currently have a "JYETech DSO112A", which looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3183"><img src="https://img.incoherency.co.uk/3183/thumb"></a></p>
<p>It sucks, and I am kind of in the market for something better. The Rigol DS1054Z comes relatively-well recommended, but it seems quite proprietary, and for example
some features from a more expensive model are locked behind a software gate. I want to use software that helps me as much as it can, not software that views me as an adversary
to its master's business model.</p>
<p>It also seems to me that even the best user interface on a physical oscilloscope wouldn't be able to beat a proper keyboard-and-mouse GUI, and I expect it would be
possible to make a better oscilloscope for less money if the "data collection" part were performed by dedicated hardware and the "presentation" were performed
on a PC. But it seems like all of the scopes that work this way are considered inferior, I don't really know why.</p>
<p>So if you have any recommendations for oscilloscopes or logic analysers that you think I might like, please email me. I'm not averse to a hardware UI, but I am <i>quite</i> averse
to proprietary software.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/scamp-alu-card.html</link>
   <guid>http://incoherency.co.uk/blog/stories/scamp-alu-card.html</guid>
   <pubDate>Sat, 06 Feb 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Designing the instruction set for my TTL CPU</title>
   <description><![CDATA[I (believe I) am making good progress on designing the TTL CPU. Most of the actual CPU design is
relatively stable now, and bug discoveries in the hardware design are infrequent, so now I get to move up
a level and work on the instruction set. After that, it's just the bootloader, operating system, and
application software. Oh, and the small matter of the physical hardware assembly...]]></description>
   <content:encoded><![CDATA[<p>I (believe I) am making good progress on designing the TTL CPU. Most of the actual CPU design is
relatively stable now, and bug discoveries in the hardware design are infrequent, so now I get to move up
a level and work on the instruction set. After that, it's just the bootloader, operating system, and
application software. Oh, and the small matter of the physical hardware assembly...</p>
<p>While trying to get the CPU
executing code correctly in the test harness, I spent most of a day solving problem-after-problem that each ultimately came down
to "the carry flag is set when I didn't expect it". It turns out that having the carry input enabled by default
was <i>way</i> more of a footgun than <a href="https://incoherency.co.uk/blog/stories/ttl-cpu-progress.html">even I predicted</a>. I
briefly considered adding a control bit to enable it where wanted, but decided it was simpler just to get rid.</p>
<p>My original intention for the carry flag was that it would make it easier to write code that does arithmetic
with values wider than 16 bits, but this is possible even without a carry input, and personally I have never used a carry flag in
my life, so I don't think I'll miss it (mostly because it's not exposed in C, and my mind works like C).</p>
<p>Following the tradition of computers named with <a href="https://en.wikipedia.org/wiki/ENIAC">contrived</a>
<a href="https://en.wikipedia.org/wiki/EDSAC">backronyms</a>, I'm thinking of calling the computer "SCAMP",
for something like "Simple Computing and Arithmetic Microcoded Processor". But I'm interested in better, so let
me know if you think of something.</p>
<p><h2>Goals</h2></p>
<p>The goals of instruction set design, for me, are:</p>
<p><ul>
<li>It should be easy to guess which instructions are available without consulting the documentation</li>
<li>It should not be needlessly difficult to write programs</li>
<li>Common operations should be fast</li>
</ul></p>
<p>There is some tension here, because one way to make common operations fast is to make non-orthogonal instructions
that do quite specific things, but that then makes it harder to predict which specific addressing modes are available
for which instructions.</p>
<p>I'm not sure I've done a particularly good job of meeting any of these goals, but I also don't think I could do a lot
better, given the limitations of the hardware design.</p>
<p><h2>Documentation</h2></p>
<p>Even though I've invented the instruction set myself, I find good documentation crucial. Trying to write assembly
language without a decent reference is an exercise in frustration.</p>
<p>The best assembly language reference I have ever
used is the <a href="https://clrhome.org/table/">clrhome Z80 instruction set table</a>. It has a 16x16 grid showing
every 1-byte opcode at a glance, with more information available when you hover over a particular instruction.</p>
<p>I have copied the style in <a href="https://incoherency.co.uk/interest/table.html">my own
instruction set cheatsheet</a>:</p>
<p><a class="img" href="https://incoherency.co.uk/interest/table.html"><img src="https://img.incoherency.co.uk/3171"></a></p>
<p>I also used coloured cells to visually group similar instructions together. Initially I was planning to do the hover effect with JavaScript,
but it's <a href="https://stackoverflow.com/a/9739105">surprisingly easy to do with pure CSS</a>.</p>
<p>You can kind of view parts of the instruction table as a "periodic table of instructions", which makes it easy to tell if some
obvious orthogonality is missing (for example, if an addressing mode exists for <tt>and</tt> but not <tt>sub</tt>, then the
rows won't match). I've tried to lay it out in a way that naturally lends itself to adding extra addressing modes to existing
instructions without disturbing the rest of the layout, but it's relatively likely that at least some of the opcodes
will change.</p>
<p>The instructions are implemented with microcode, and the instruction set cheatsheet is <a href="https://github.com/jes/ttl-cpu/blob/master/asm/mk-table-html">generated automatically</a>
from the microcode source, via an intermediate <tt>instructions.json</tt> file which describes the instruction set.</p>
<p><tt>instructions.json</tt> is also used to configure the assembler. This way, whenever I make a change to the instruction set (including adding/removing
instructions, or moving around existing instructions), it is automatically reflected in the assembler and the documentation with no code
changes required. This gives me good confidence that the assembler is always generating the correct opcodes, and that the documentation
always matches, which removes a big source of problems.</p>
<p>I also decided to include the microcode implementing each instruction in the hover popup on the cheatsheet.
This way, if (ha) I have written any microcode bugs, I have half a chance of debugging the microcode by accident while trying to debug the program.
It also might be useful in case I have any doubts about how an instruction works.</p>
<p><h2>Pseudo-registers</h2></p>
<p>One of the peculiar features of my CPU is that it has a mechanism for putting the low bits of the instruction word on the bus, but with the upper
bus bits set to 1. This allows instructions to use the low 8 bits of the instruction word to reference an address in the top 256 addresses of
memory.</p>
<p>To keep things simple, the CPU has a serious shortage of real registers: it has the bare minimum of registers required to be able to give 2 operands
to the ALU. Namely, 2.</p>
<p>2 registers is not enough to do anything interesting with, so intermediate values will have to go out to memory.</p>
<p>It would be really inconvenient to have to manually pick global addresses for all intermediate values, so I've given the assembler a special syntax for
referring to addresses in the top 256 words. They're called "pseudo-registers" and are called <tt>r0</tt> to <tt>r255</tt>. This is similar
to <a href="https://www.nand2tetris.org/project04">an idea from Nand2Tetris</a>, where the first 16 words are referred to as <tt>R0</tt> to <tt>R15</tt>,
except I couldn't put my pseudo-registers in the first 256 words, because the first 256 words are backed by ROM.</p>
<p>I'm using <tt>r255</tt> as a stack pointer, and there are dedicated instructions that use it this way, and <tt>r254</tt> for various purposes,
as we'll see below.</p>
<p>In the instruction set cheatsheet, an <tt>r</tt> operand is just syntactic sugar for an <tt>(i8h)</tt> operand, i.e. an address in the top 256
words, indexed by the low 8 bits of the instruction word.</p>
<p><h2>Microcode</h2></p>
<p>The microcode source is in <a href="https://github.com/jes/ttl-cpu/blob/master/ucode/ucode.s">ucode/ucode.s</a> in the github repo,
with documentation in <a href="https://github.com/jes/ttl-cpu/blob/master/doc/UCODE.md">doc/UCODE.md</a>.</p>
<p>Currently I am manually implementing every single instruction, although it might be better to write a program to generate the
microcode source from a more high-level description. For example, <tt>add</tt>, <tt>sub</tt>, <tt>and</tt>, <tt>or</tt>, <tt>nand</tt>, and
<tt>nor</tt> each currently support exactly the same addressing modes and differ only by the ALU operation that they select. This is
an obvious candidate for writing a program to generate all the different versions, instead of maintaining them manually.</p>
<p>Here is a selection of instruction implementations, to give you a flavour of how the microcode works. Note that things like <tt>Y-1</tt>
are syntactic sugar <a href="https://github.com/jes/ttl-cpu/blob/master/ucode/uasm#L53">in uasm</a> for setting the ALU control bits.
There is not a general mechanism to compute arbitrary arithmetic. <tt>Y-1</tt> is just <tt>NX EY F</tt>. I have written up
<a href="https://github.com/jes/ttl-cpu/blob/master/doc/ALU.md">an ALU reference</a>.</p>
<p><pre><code>add x, i8l:
    IOL YI  # Put the low 8 bits of the instruction word (called i8l) on the bus, and load the bus into y
    XI X+Y  # Use the ALU to put x+y on the bus, and load the bus into x</code></pre></p>
<p>Should be self-explanatory.</p>
<p><pre><code>push x: 
    -1 AI   # Use the ALU to put -1 (0xffff) on the bus, and load it into the address register
    MO YI   # Put M[0xffff] on the bus, and load it into y
    MO AI   # Put M[0xffff] on the bus, and load it into the address register
    MI XO   # Put x on the bus, and load it into M[M[0xffff]]
    -1 AI   # Use the ALU to put -1 (0xffff) on the bus, and load it into the address register
    Y-1 MI  # Put Y-1 on the bus, and load it into M[0xffff]</code></pre></p>
<p><tt>M[0xffff]</tt>, aka <tt>r255</tt>, aka <tt>sp</tt>, is the stack pointer. The microcode dereferences the stack pointer,
stores <tt>x</tt> at the address the <tt>sp</tt> points to, then writes <tt>sp-1</tt> into <tt>sp</tt>. (The stack grows
downwards).</p>
<p><pre><code>tbsz r, i16:
    IOH AI     # Put i8h in the address register
    MO XI      # Load from (i8h) into x
    PO AI      # Load program counter (currently pointing at the i16) into the address register
    MO YI P+   # Load the i16 into y and increment PC
    X&amp;Y        # Compute X&amp;Y with the ALU, discard the result, and just use it to set the flags
    PO JNZ P+  # Put the PC on the bus, jump if flags register says "not zero", increment PC</code></pre></p>
<p>This instruction boils down to "skip the next 1-word instruction if <tt>r &amp; i16</tt> is zero". Mostly it might be easy
to follow, but the final step is confusing. The part to understand is that the <tt>JMP</tt> input to the program counter
has higher priority than <tt>P+</tt>. <tt>JMP</tt> is computed by combining the jump flags with the flags register, in this
case <tt>JNZ</tt> means <tt>JMP</tt> will be enabled if the <tt>Z</tt> bit is not set. So in the event that <tt>Z</tt> is set,
<tt>P+</tt> applies and we skip the next instruction, but in the event that <tt>Z</tt> is <i>not</i> set, the <tt>JMP</tt>
means the PC loads its output back in, so the <tt>P+</tt> bit has no effect. Quite tricksy.</p>
<p><pre><code>xor x, y:
    -2 AI      # Set address register to 0xfffe 
    MI X|Y     # Set r254 = X|Y
    YI ~(X&amp;Y)  # Set Y = ~(X&amp;Y)
    MO XI      # Set X = r254
    XI X&amp;Y     # Set X = X&amp;Y</code></pre></p>
<p>This computes <tt>x^y == (x|y) &amp; ~(x&amp;y)</tt> ("x or y, but not both"), using <tt>r254</tt> as scratch space.</p>
<p><h2>Weirdness</h2></p>
<p>The instruction set I'm using at the moment has quite a lot of weirdness unfortunately, but it all makes sense if you understand
the underlying limitations, which are:</p>
<p><ol>
<li>The sequencer only counts from 0 to 7.</li>
<li>There are only 2 general-purpose registers.</li>
<li>The ALU can only generate constants 1, 0, -1, and -2.</li>
<li><tt>xor</tt> and bitwise-shift-right are not natively supported by the ALU, and are achieved through funny tricks.</li>
</ol></p>
<p><h3>Instructions conspicuous by their absence</h3></p>
<p>The first 2 steps of microcode for every instruction are just loading the program counter into the address register,
and then loading the instruction word into the instruction register. That leaves 6 clock cycles available for
actual operations. Any operations that need more than 6 cycles can not be implemented with a single instruction.</p>
<p>It would be natural for the existing instruction set to also include <tt>push r</tt>, <tt>pop r</tt>, <tt>xor x, r</tt>, <tt>add x, (++r)</tt>, and <tt>shl3 r</tt> (bitwise shift-left by 3
on a pseudo-register, currently <tt>shl3</tt> only exists for <tt>x</tt>).
Unfortunately these would all go over the cycle limit, so they just have to be excluded.</p>
<p>In principle I could add another bit to the sequencer so that it counts from 0 to 15, but the microcode addressing is not
very flexible, so this would double the size of the microcode ROM for <i>relatively</i> little benefit.</p>
<p>The other instructions conspicuously absent are <tt>shr</tt> instructions for a bitwise shift-right (comparable to the <tt>shl</tt> instructions), and any
instructions of the form <tt>foo r, r</tt>.</p>
<p><tt>foo r, r</tt> instructions do not exist because <tt>r</tt> is just shorthand for <tt>(i8h)</tt>, and there can only be one <tt>i8</tt> value
per instruction because it comes from the lower 8 bits of the instruction word.
In practice, <tt>foo r, r</tt> instructions (e.g. "<tt>add r0, r1</tt>") can be written and assembled just fine, because they can be provided
by <tt>foo r, (i16)</tt> and <tt>foo (i16), r</tt>. Any <tt>i8</tt> value can be generated by an <tt>i16</tt>, at the cost of an extra word of memory
(to store the <tt>i16</tt>) and typically a single extra clock cycle.</p>
<p>The <tt>shl</tt> instructions are implemented with repeated adding (<tt>x&lt;&lt;1 == x+x</tt>), but
<tt>shr</tt> can not obviously be implemented in microcode at all, because the ALU provides no mechanism for it.</p>
<p><h3>Instructions conspicuous by their presence</h3></p>
<p>The <tt>tbsz r, i16</tt> and <tt>sb r254, i8l</tt> instructions are very unusual. They exist purely to implement a "bitwise shift-right 8" operation,
which I expect to be useful in unpacking 2 bytes from a single 16-bit word, although it turns out they can actually be used to implement bitwise shift-right of
any value greater than or equal to 8.</p>
<p><tt>tbsz r, i16</tt> is "test bits and skip if zero". It takes a pseudo-register and a 16-bit mask. If <tt>r &amp; i16</tt> is zero, then execution
skips over the next 1-word instruction.</p>
<p><tt>sb r254, i8l</tt> is "set bits". It operates only on <tt>r254</tt>, because it needs to take an 8-bit argument to know which bits to set, and it
needs to fit in a single word so that <tt>tbsz</tt> can skip it (which means it can't take an <tt>i16</tt> argument).</p>
<p>It is kind of remarkable that it is possible to implement <tt>shr8</tt> with just 2 complementary instructions like this. It turns out that
implementing an efficient
shift-right 8 on my CPU is one of those things that's
<a href="https://www.youtube.com/watch?v=LA_DrBwkiJA">only <i>slightly</i> impossible, which is not the same as completely impossible</a>.
OK, "efficient" is maybe a stretch. Computing shift-right 8 with <tt>tbsz</tt> and <tt>sb</tt> takes up to 112 clock cycles, which is about 5x as
long as a shift <i>left</i> by 8. But it's nowhere near as bad as computing a shift-right manually with
<tt>ld</tt>, <tt>and</tt>, <tt>jz</tt>, and <tt>or</tt>.</p>
<p><h3>Different purposes for r254 for no obvious reason</h3></p>
<p><tt>r254</tt> is (ab)used as:</p>
<p><ul>
<li>return address for <tt>call</tt>/<tt>ret</tt>.</li>
<li>operand of <tt>sb</tt>.</li>
<li>scratch space for <tt>xor</tt>.</li>
</ul></p>
<p>The microcode can't directly include any numeric values. It can only encode on/off for each of the control signals.
In the general case, main memory (including instruction operands)
is the only source for numeric values. But <i>addresses</i> are also numeric values, which means microcode has no way
to generate hardcoded addresses. The 4 exceptions are 0, 1, -1, and -2, which can all be generated in a single cycle using the ALU,
and without clobbering either the <tt>x</tt> or <tt>y</tt> register. 0 and 1 aren't super useful as addresses because they are both in ROM. But -1
and -2 correspond to <tt>r255</tt> and <tt>r254</tt> respectively. <tt>r255</tt> is designated as the stack pointer, which leaves
<tt>r254</tt> available as convenient scratch space.</p>
<p>In principle you could create any address in memory by using -1 and the <tt>y</tt> register, (e.g. load -1 into <tt>y</tt>, then load <tt>y-1</tt>
into <tt>y</tt>, then <tt>y-1</tt> again, etc.). It turns out we <i>could</i> modify the basic <tt>call</tt>/<tt>ret</tt> instructions to use <tt>r253</tt> for the return address
instead of <tt>r254</tt>,
so that it doesn't get clobbered by <tt>xor</tt> and <tt>sb</tt>.</p>
<p>The downside is this would push the indirect call (<tt>call (i16)</tt>)
and "return with stack pointer adjustment" (<tt>ret i8l</tt>) instructions over the cycle limit. Better to just reuse <tt>r254</tt>
in my opinion, especially given that <tt>r254</tt> already needs to be stashed in a lot of cases because it would be clobbered by nested
function calls anyway.</p>
<p><h3>The y register is only available for xor</h3></p>
<p>The 2 general-purpose registers (from the hardware perspective) are <tt>x</tt> and <tt>y</tt>, and they are the operands to the ALU. This means
any operation that needs 2 operands to the ALU needs to overwrite the contents of both registers. In most cases, I
am not exposing the <tt>y</tt> register in the instruction set at all, so from the programmer's perspective, only <tt>x</tt> is
available as a general-purpose register.</p>
<p>Unfortunately the <tt>xor</tt> implementation takes all 6 available cycles even if it directly operates on just the <tt>x</tt> and
<tt>y</tt> registers. That means there's no way for it to load an operand from memory. Rather than just say "<tt>xor</tt> doesn't
exist, you have to compute it manually", I thought it was better to provide an <tt>xor</tt> instruction that operates directly on
<tt>y</tt>, along with some <tt>ld y, *</tt> instructions to get values into <tt>y</tt>.</p>
<p>But it certainly makes the instruction set ugly: if <tt>xor</tt> didn't exist, then <tt>ld y, *</tt> wouldn't have to exist, and
then we could pretend that the <tt>y</tt> register doesn't exist at all, and wouldn't have to document which instructions clobber
it.</p>
<p><h2>Testing</h2></p>
<p>To test the CPU, I have a "<a href="https://github.com/jes/ttl-cpu/blob/master/bootrom.s">boot ROM</a>" that outputs consecutive
values to device 0. It creates these values lots of different ways, to test out different parts of the instruction set.
The <a href="https://github.com/jes/ttl-cpu/blob/master/cpu_tb.v">CPU testbench</a> just runs the CPU for 2000 cycles and verifies
that the program outputs consecutive values, and the correct number of them. This testbench is executed using both the high-level
Verilog and TTL-equivalent Verilog implementations of the CPU.</p>
<p>I also have a <a href="https://github.com/jes/ttl-cpu/blob/master/verbose_tb.v">verbose testbench</a> that does almost exactly the same thing,
but enables the "DEBUG" parameter. This causes the CPU to dump its entire state once per clock cycle. This also runs for both the
high-level and TTL-equivalent implementations, and <a href="https://github.com/jes/ttl-cpu/blob/master/run-tests.sh#L34">the outputs are compared</a> to ensure
that the 2 CPU implementations not only both work, but both work <i>identically</i>. I caught a few subtle bugs this way where one implementation
or the other had some undefined state that didn't directly affect the results from the instructions that were running, but plausibly could do in other cases.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/instruction-set.html</link>
   <guid>http://incoherency.co.uk/blog/stories/instruction-set.html</guid>
   <pubDate>Sun, 31 Jan 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Progress on my TTL CPU design</title>
   <description><![CDATA[I want to make a CPU out of physical 74xx TTL chips. I have now implemented most of the parts using a subset of Verilog that
maps directly to TTL chips, and I wanted to write a bit about the design.]]></description>
   <content:encoded><![CDATA[<p>I want to make a CPU out of physical 74xx TTL chips. I have now implemented most of the parts using a subset of Verilog that
maps directly to TTL chips, and I wanted to write a bit about the design.</p>
<p>Before we start, I'll warn you now: this is another of my long, rambling, brain-dump-type posts. Don't read it if you don't want to.</p>
<p>If you want to look at any of the code, it's all in my <a href="https://github.com/jes/ttl-cpu">ttl-cpu github project</a>.</p>
<p><h2>Choosing a word size</h2></p>
<p>I found that a lot of the design decisions are inter-dependent, which makes starting from a blank canvas
particularly difficult. Choosing the word size is one of the decisions that both affects, and can be affected by, the
implementation of everything else.</p>
<p>There were really 2 things I wanted to know to choose a word size:</p>
<p><ol>
<li>how wide do I want addresses to be?</li>
<li>do I want addresses to fit in a single register, or do I want to concatenate registers to form addresses?</li>
</ol></p>
<p>I kind of wanted to use an interesting non-multiple-of-8 word size, just because one doesn't get many chances to
use such an oddball system, and building your own CPU is a great opportunity to do it. Unfortunately,
it isn't really a sensible choice with TTL chips. The 74377 register stores 8 bits. The 74244 buffer buffers 8 bits.
If you use a word size that doesn't divide by 8 then you end up
just leaving unused silicon lying around for no good reason. If the hardware is going on the board anyway, it might as well
get used.</p>
<p>So then the sensible choices for address width are 8 bits, 16 bits, 24 bits, and 32 bits. Clearly 8 bits is not enough, and 32
bits is way too large. 24 bits might be fine, but I don't really see myself wanting 16 megabytes of address space, so I
picked 16 bits for the address size.</p>
<p>And then we have to decide whether we're making an 8-bit computer that has to make addresses by sticking 2 registers together,
or a 16-bit computer that doesn't. If we need to support 16-bit addresses then we need at least the address bus to be 16 bits
wide, and we need enough register space overall to support a 16-bit address and an 8-bit value. It doesn't seem much of a
stretch to just say both registers will support a 16-bit value, and then we save some complexity in the control logic at the
cost of having 2 16-bit registers instead of just 1, and having a 16-bit wide ALU.</p>
<p>There are ways to get around making the ALU match the width of the registers, but I'm not sure it's worth it. The Z80 uses
a 4-bit ALU, and 8-bit operations take 2 cycles (one for the low nybble and one for the high nybble).
In the limit case the ALU only really needs to operate
on 1 bit at a time, with wider operations performed serially. I was recently informed that the <a href="http://www.corestore.org/8s.htm">PDP-8/S</a>
worked this way, although it was apparently extremely slow and not a commercial success.</p>
<p><h2>Block diagram</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/3169"><img style="max-width:500px; max-height:500px" src="https://img.incoherency.co.uk/3169"></a></p>
<p>The diagram is roughly colour-coded to indicate parts that have similar functions. The small subscript numbers show
how many bits a register holds, or whatever else makes sense in context.</p>
<p>The single-width arrows carry a single bit of information. The CPU is controlled by the control bits that come out
of the microcode ROM. These are then plugged into the labels. For example, one of the control bits is <tt>AI</tt>,
which is connected to the "Load" signal of the address register. If a microinstruction enables <tt>AI</tt>, then
at the next rising edge of the clock, the address register takes on the contents of the bus.</p>
<p>The one thing that is kind of fudged in the diagram is that <tt>JMP</tt> just magically appears as a control signal
from the microcode, but in reality there would be some logic to combine the jump flags output by the microcode with the
flags from the flags register. I just haven't yet worked out where that logic is going to live.</p>
<p>Also note that while the instruction register is 16 bits wide, only 8 bits are used for the opcode, so only 8 are
used to lookup the address in the microcode ROM, which (combined with 3 bits from the sequencer) is why the microcode ROM only needs 2048 entries.</p>
<p><h2>Chip counts</h2></p>
<p>Here is my best guess for the number of chips I'll need for the CPU:</p>
<p><table border>
<tr><th>Module</th><th>Chips</th></tr>
<tr><td>ALU</td><td>39</td></tr>
<tr><td>Program counter</td><td>6</td></tr>
<tr><td>Instruction register</td><td>6</td></tr>
<tr><td>Control bits decoding</td><td>4</td></tr>
<tr><td>X register</td><td>2</td></tr>
<tr><td>Y register</td><td>2</td></tr>
<tr><td>Address register</td><td>2</td></tr>
<tr><td>Sequencer</td><td>2</td></tr>
<tr><td>Microcode ROM</td><td>2</td></tr>
<tr><td>Flags register</td><td>1</td></tr>
<tr><th>Total</th><th>66</th></tr>
<table></p>
<p>In addition to this, I expect 2 chips for the RAM, 2 chips for the ROM, at least 1 in the clock, and some unknown amount more
to drive the serial ports and disk. But the whole computer will easily use fewer than 100 physical chips.</p>
<p><h2>Microcode</h2></p>
<p>Turning instructions into control signals was one of the things that most baffled me. <a href="https://nand2tetris.org/">Nand2Tetris</a>
kind of glossed over this by making the instructions themselves directly set the control signals.</p>
<p>I found Ben Eater's 3-part video series on <a href="https://www.youtube.com/watch?v=dXdoim96v5A">8-bit CPU control logic</a> to be superb,
it clarified everything for me.
If you have a good working knowledge of bitwise logic, but you don't quite see how it all adds up into a working
CPU, just watch those 3 videos and it will all be totally clear. I can't recommend it highly enough.</p>
<p>The trick is that you don't need to manually derive logic to turn instructions into control signals. You can just make a lookup table
on a ROM
that is addressed by the current opcode and the current clock cycle number, and the output of the lookup table gives you the control
signals. The contents of the ROM are called <a href="https://en.wikipedia.org/wiki/Microcode">microcode</a>. More flexible microcode
systems can keep a "micro-program counter" which is more than just "opcode + cycle count", and allow for a "micro-jump",
so that the ROM is not mostly wasted on sparsely encoding short instructions.</p>
<p>I currently need to generate 24 control bits, which would require 3x ROM chips if they each have 8-bit output, and if I need
even 1 more bit, then I need a 4th chip. But a lot of the control
bits don't make sense at the same time (for example I never want more than 1 module driving the bus at the same time, and I only need to
select an ALU operation if the ALU is driving the bus, otherwise I don't care what the ALU does). For this reason I came up with a simple encoding
that allows me to select all useful combinations of control bits with a microinstruction that is only 14 bits wide, which also leaves me with
2 signals spare to use for anything else I can think of.</p>
<p>There is more information about my control bits and microcode encoding in the <a href="https://github.com/jes/ttl-cpu/blob/master/doc/UCODE.md">doc/UCODE.md</a>
file in my git repo.</p>
<p>I have also written a simple <a href="https://github.com/jes/ttl-cpu/blob/master/ucode/uasm">microassembler</a> to turn microcode into hex
that will eventually be written to the ROM.</p>
<p>Here's example microcode that computes <tt>X = X + Y</tt> in a single cycle:</p>
<p><pre><code>EO XI EX EY F</code></pre></p>
<p><tt>EO</tt> enables the ALU output on to the bus. <tt>XI</tt> enables X register input from the bus (i.e. X register gets the ALU output, in this case). <tt>EX</tt>, <tt>EY</tt>, and <tt>F</tt> select
the ALU operation (in this case: enable the X and Y inputs, and set the "function" bit, i.e. request addition instead of bitwise AND). The result
is that the current value of X and Y are enabled as inputs to the ALU, the output of the ALU comes from the adder, and the output of the ALU goes on to
the bus. So far this is purely combinational logic, and it all happens "immediately". Upon the next rising clock edge, the value from the bus (which
is X+Y) is clocked into the X register. At that point the X register takes on its new value, which then propagates through to the ALU input, and
is reflected in the new ALU output, but it is not taken into the X register until there is another rising clock edge. But before the next rising edge, there'll
be another falling edge, so we'll have a new microinstruction with potentially new control bits.</p>
<p>Ben Eater's CPU includes a control bit called <tt>IO</tt> which causes the instruction register to output its lower 4 bits on to the 8-bit bus,
with the upper 4 bits of the bus set to 0. In this way you can use the upper bits of the instruction to select an opcode and the lower bits to
encode an immediate small-valued constant.</p>
<p>I have a comparable bit called <tt>IOL</tt> which puts an immediate 8-bit constant from the low bits of the instruction register on the bus. I
also added <tt>IOH</tt> which does the same thing except with the upper 8 bits set to 1. That means <tt>IOH</tt> can be used to create immediate
constants from 0xff00 to 0xffff, which is useful for immediate small-valued <i>negative</i> constants, and for addresses in the top page of memory.
I propose using the top page of memory as scratch space for complicated instructions, and for a stack pointer, and for anything else that is
worth being able to access in a minimum of clock cycles. The cool part is that when using an instruction that uses an address in the
top page, you always get to pick which address it is, so for example you could use the same <tt>push</tt> instruction to handle up to 256 independent stacks.</p>
<p><h2>Sequencing</h2></p>
<p>The lower 3 bits of the microcode ROM address come from the 3-bit "T-state". The T-state counts up by 1 on each falling clock edge, which updates the
microcode address, which gets all the control bits set and stable ready for the next rising clock edge, at which time registers take in
new values and the program counter increments. The T-state is reset to 0 either when it wraps around after 7, or when the <tt>RT</tt> control bit is set, which allows the
microcode to finish an instruction in fewer than 8 cycles.</p>
<p>The first 2 T-states always have the same microcode:</p>
<p><pre><code>T0:  PO AI    # load address from program counter
T1:  MO II P+ # load instruction register from memory, increment PC</code></pre></p>
<p>After this, the instruction register contains the current instruction, and microcode specific to that instruction is executed. Once the instruction
is finished, it remains in the instruction register, and the next cycles tick through the first 2 states for the instruction that <i>just executed</i> before we
know what the next one is. So the first 2 T-states need the same microcode for every instruction, because we get the first 2 T-states
from the <i>previous</i> instruction's microcode.</p>
<p>For this reason I thought it might be worth taking the first 2 T-states out of the ROM, and letting the sequencer count up to 10, and providing
8 customisable steps of microcode per instruction instead of only 6. But I don't know that it's worth adding extra logic for.</p>
<p><h2>Development techniques</h2></p>
<p>I have not designed a lot of electronics before, and when I have I have basically used the <a href="http://wiki.c2.com/?FeynmanAlgorithm">Feynman
Algorithm</a> to ensure that I had designed it correctly. Unfortunately, I'm not Richard Feynman, so it doesn't work very well, and I
normally end up getting it wrong.</p>
<p>For this project I have set up a development environment that is much closer to working on <i>software</i> than on electronics.</p>
<p>I am creating each part of the CPU in Verilog, and writing a testbench that checks that it works the way I expect, and then reimplementing
the part in a subset of Verilog that only uses primitives which are available in 74xx TTL chips (which I have got from <a href="https://github.com/TimRudy/ice-chips-verilog">Tim
Rudy</a>). Then I can verify that the TTL implementation works the same as the high-level Verilog implementation, so that when
I finally build it out of physical chips it is guaranteed to work on the first try. How hard can it be?</p>
<p>The TTL-Verilog implementations of the parts are in the <tt>ttl-*.v</tt> files in <a href="https://github.com/jes/ttl-cpu">the git repo</a>. Using
a subset of Verilog that only allows for incorporation of other parts by reference, and wire connections, is basically the same as
using the HDL in the Nand2Tetris course.</p>
<p>My <a href="https://github.com/jes/ttl-cpu/blob/master/run-tests.sh">test harness</a> is pretty janky, but does the job.
It is a shell script that uses <a href="http://iverilog.icarus.com/">Icarus Verilog</a> to compile
the Verilog source into a Linux executable. Then each Verilog part has a testbench part (also implemented in Verilog) that loads the part it is testing,
drives it in various different ways, and prints out an error message if anything seems wrong. To make sure that the TTL implementation also
works, the shell script uses <tt>sed</tt> to edit the testbench source to include the TTL version of the part instead of the high-level Verilog
version, and then runs the test again.</p>
<p><h2>Other stuff</h2></p>
<p>It would be relatively easy to add extra functions to the ALU, selected by 1 of the unused bits from the microinstruction. My first
thought was to add an XOR function to the ALU, but it turns out that's easy enough to do with just 3 trips through the existing ALU
(<tt>x^y == (x|y) &amp; ~(x&amp;y)</tt>). Another obvious feature that's missing is bitwise shift. A left-shift is relatively easy
to create by composing addition (<tt>x<<1 == x+x</tt>, <tt>x<<2 == (x+x) + (x+x)</tt>, etc.), but right-shift is not obviously trivial.</p>
<p>I expect bitwise right-shift will be particularly important for unpacking 2 bytes from 1 16-bit word. The ALU
already has native support for AND and OR, so maybe testing individual bits
would be suitable, especially if it could take advantage of a dedicated instruction for something like "test-and-set-bit":</p>
<p><pre><code>// compute y = x>>8
int y = 0;
if (x &amp; 0x8000) y |= 0x80;
if (x &amp; 0x4000) y |= 0x40;
if (x &amp; 0x2000) y |= 0x20;
if (x &amp; 0x1000) y |= 0x10;
if (x &amp; 0x0800) y |= 0x08;
if (x &amp; 0x0400) y |= 0x04;
if (x &amp; 0x0200) y |= 0x02;
if (x &amp; 0x0100) y |= 0x01;</code></pre></p>
<p>Currently the carry input to the ALU is always enabled, and if you don't want it you have to explicitly clear it. Clearing the carry flag
takes 1 cycle of microcode, and can't currently be done at the same time as much else as it requires the <tt>EO</tt> bit
to be set, which precludes any other module driving the bus. This means there is an incentive to
make the "with carry" version of arithmetic operations be the default one, because it saves wasting a cycle on clearing the flag.</p>
<p>The problem is that this is liable to turn into quite the footgun if the carry flag is ever left on by something you didn't think of,
resulting in some operations occasionally being off-by-1 by surprise.</p>
<p>For this reason I am considering putting an AND gate on the carry input to the ALU, with 1 of the inputs coming from the existing carry
flag, and the other coming from a currently-unused bit of the microcode instruction. That way the microinstructions that want
the carry input will explicitly enable it, and otherwise the "safety" will be on and I won't get shot in the foot.</p>
<p>Speaking of footguns: I thought it might be interesting to replace some of the microcode ROM with "microcode RAM". We could dedicate some portion of
the opcode space to instructions that are created at runtime! I don't even think this would take all that much logic. It would need
a single control bit that enables input from the data bus to the microcode RAM, addressed by the existing address register, and
a dedicated instruction in the microcode ROM to access it. If I wanted to dedicate half of the opcode space to this, then
I'd only need 2 extra chips to provide the microcode RAM, and 4 4-bit multiplexers that select the microinstruction from either the ROM or the RAM based
on the high bit of the instruction register. So only 6 extra chips in total. Maybe it's worth doing!</p>
<p>My initial objection to microcode RAM was going to be that I wouldn't want a full 50% of the opcode space to be dedicated to RAM, so
I'd need even more chips to work out whether a given instruction is backed by microcode in ROM or RAM.
But actually as long as the 128 opcodes implemented in the ROM contain enough instructions for a bootloader to work, then we can instantiate the
rest when the system boots, and just leave a small handful of opcodes free for applications to create.</p>
<p>I think it would be surprisingly easy to add extra registers or other modules to the CPU after it has been built (although I don't actually
expect that I will). The "bus input" and "bus output"
values from the microinstruction have a few unused encodings. I could run the control bits from these unused encodings alongside all of the bits
that are actually used, and then if I wanted to add a new register, I could just plug a new card into the bus, connect up the spare control bits, and add
some microcode to use it.</p>
<p>I said in the <a href="https://incoherency.co.uk/blog/stories/cpu-design.html">last CPU design post</a> that I'd want to support interrupts, but having done a bit
more thinking on that I don't know if I will. I envisage running a very CP/M-like operating system on it, and polling for keyboard input
really isn't a burden for the kinds of things I'm likely to be running. The only downside of missing interrupts is that <tt>^C</tt> won't
be able to interrupt an errant program, but in my experience that doesn't work on CP/M anyway even on machines that <i>do</i> support interrupts,
unless the program is already polling the keyboard.</p>
<p>I am currently planning to leave almost all of the internal state undefined when the CPU is reset, resetting only the program counter and
sequencer. That will mean the registers could contain arbitrary contents. I don't think this will be a problem as long as the boot ROM
doesn't make any assumptions about them.</p>
<p>I haven't decided yet whether the CPU will have a "backplane" that all of the other modules plug into, or whether it will be
some system of cards that have for example a female bus connector on the top and a male one on the bottom, so that they can be
stacked together.</p>
<p><h2>Compared to Z80</h2></p>
<p>The Z80 has separate address and data buses. To keep things simple, I only have one bus, and I have a dedicated register to
take an address from the bus and store it, to drive the address lines of the memory. The downside of only having one bus is that it
~always takes at least 2 cycles to read from memory, even if you already have the address immediately to hand in a register, because it
takes an extra cycle to load it into the address register.</p>
<p>On the Z80, I/O is performed by putting the I/O device address in the low 8 bits of the address bus (the upper 8 bits are ignored for I/O),
and data on the data bus. I envisage doing the same thing. I initially thought I could use the main bus to provide both the device
selection (e.g. in the upper 8 bits) and the data (e.g. in the lower 8 bits), and while this would work for output, it won't be
so easy for input, because the bus would have to be half-driven by the thing setting the I/O device selection, and half-driven by the
I/O device itself. Easier just to separate them. And having 16 bits of device selection space means I can probably just dedicate an
entire bit to selecting the device, which means I probably won't need any I/O address decoding logic.</p>
<p></p>
<p>
<h2>Compared to Nand2Tetris</h2></p>
<p>The main thing my CPU has in common with the Nand2Tetris CPU is the ALU. I really liked the ALU from Nand2Tetris, and have used it almost
verbatim, except I inverted the "zero X" and "zero Y" inputs to be "enable X" and "enable Y" instead. This way the X and Y inputs
can be turned into 0 using AND gates instead of multiplexers. I.e. the X input comes from <tt>X & EX</tt> instead of <tt>ZX ? 0 : X</tt>.</p>
<p>I didn't like that Nand2Tetris put the code in a completely separate address space to the data, and am pleased to have moved away from that.</p>
<p>I also didn't like that Nand2Tetris sets the control bits directly in the instruction, and I think using microcode is a definite improvement
for my purposes (although possibly not for the pedagogical purposes of the Nand2Tetris course).</p>
<p></p>
<p></p>
<p><h2>Compared to Ben Eater's breadboard CPU</h2></p>
<p>My CPU is very heavily influenced by Ben Eater's design. Even my block diagram is laid out in the same order as his breadboards.</p>
<p>The principle differences are that I am using a 16-bit bus instead of 8-bit, and I am using 16-bit addresses instead of 4-bit. Again, while
I think this is an improvement for <i>my</i> purposes, it is not a criticism of Ben Eater's project, which serves its pedagogical
purposes very well.</p>
<p>The Nand2Tetris ALU is quite a lot more flexible, and part of this flexibility gives it the ability to output either the X or Y input
unmodified (by setting the operation to addition and zeroing out the other operand). This means I can do away with the buffers that
enable the X and Y registers to be output directly on to the bus, because the same result can be achieved via the ALU, which already
has output buffers.</p>
<p></p>
<p><h2>Operating System thoughts</h2></p>
<p>I think the operating system will look something like CP/M in a Unix costume fancy-dress.</p>
<p>I could make CP/M support a <tt>system()</tt>-like call by swapping the currently-running
process out to disk, running the child program, and then swapping the parent back in when the child exits. We'd basically get a "process
stack", with only the top element of the stack executing at a time, instead of a traditional process tree with every element
runnable simultaneously. Starting a program would basically work like a function call.</p>
<p>In addition to allowing arbitrary programs to call other programs, this would also solve the biggest problem I have with CP/M, which
is that it has almost no ability to compose programs together. It still wouldn't provide a way to pipe data between concurrent
processes, because it's still not multitasking,
but you could implement simple text pipelines by having the shell run each command in order, with the output
in between buffered on disk, MS-DOS style.</p>
<p>In certain workflows, the system() implementation might be quite a bottleneck, so I should look at ways to optimise that: namely,
copying from memory to disk and vice versa should be done as quickly as possible, e.g. dedicated instructions to allow "output current word
to storage, increment pointer, repeat" in the minimum number of cycles.</p>
<p>I think I would do away with CP/M's "drive letter and user number" system for organising the filesystem, and use something much
more Unix-like, where all files exist in a single tree with directories and nested directories.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/ttl-cpu-progress.html</link>
   <guid>http://incoherency.co.uk/blog/stories/ttl-cpu-progress.html</guid>
   <pubDate>Sun, 24 Jan 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I want to cast some rings</title>
   <description><![CDATA[Emma and I are getting married later this year, which means we need to acquire some wedding rings.
I initially wanted to get rings made of some exotic alloy like Inconel,
but now I think I'd like to cast them myself out of gold, which means I need to learn how to cast rings. If you
know how to cast rings, perhaps you can help me learn.]]></description>
   <content:encoded><![CDATA[<p>Emma and I are getting married later this year, which means we need to acquire some wedding rings.
I initially wanted to get rings made of some exotic alloy like <a href="https://en.wikipedia.org/wiki/Inconel">Inconel</a>,
but now I think I'd like to cast them myself out of gold, which means I need to learn how to cast rings. If <i>you</i>
know how to cast rings, perhaps you can help me learn.</p>
<p><h2>The Plan</h2></p>
<p>I plan to start with aluminium. Only once I have convinced myself that I can
produce acceptable rings with aluminium do I plan to shell out for gold. If I can't get it to work with aluminium,
we'll just buy some rings that someone else has made. So I feel that there's relatively little risk in pursuing this for now.
There is a risk that I can do it with aluminium but not with gold, but that's a bridge that I'll cross if I get to it.</p>
<p>The plan for casting the rings is:</p>
<p><ol>
<li>3d print the rings in PLA</li>
<li>place the rings inside a cylindrical container ("flask") and fill the empty space with plaster</li>
<li>burn out the plastic in the furnace, leaving a void inside the plaster in the shape of the rings</li>
<li>pour molten metal into the mould</li>
<li>break away the mould</li>
<li>polish the rings until they look suitably shiny</li>
</ol></p>
<p>This process is functionally equivalent to the traditional <a href="https://en.wikipedia.org/wiki/Lost-wax_casting">lost wax</a> casting process,
except using PLA instead of hand-carved wax, leading to the name "<a href="https://all3dp.com/2/lost-pla-casting-guide/">lost PLA casting</a>".</p>
<p>It sounds easy, and indeed has been described as "super easy", but so far I've had 3 attempts and produced 0 rings.</p>
<p>In addition to the rings, I also 3d-printed a little (negative of) a pouring basin/funnel and sprue, to give me half a chance of getting the metal
into the mould:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3112"><img src="https://img.incoherency.co.uk/3112/thumb"></a></p>
<p>The pieces there are stuck together with hot glue, which I expect will burn out just as well as PLA does. That is upside down relative to how the
metal will be poured.</p>
<p><h2>Attempts so far</h2></p>
<p><h3>First attempt</h3></p>
<p>My first attempt used some of the plaster left over from my attempts at <a href="https://incoherency.co.uk/blog/stories/metal-3d-printing-first-results.html">sintering 3d-printed
bronze PLA</a>. This was over a year ago and I guess the plaster has gone off, because it did not set hard. I burnt out the plastic anyway, but I
was left with a crumbly block of plaster that broke apart as I tried to handle it.</p>
<p>I did not even try to pour metal into this mould.</p>
<p><h3>Second attempt</h3></p>
<p>Not to be defeated, I bought a new bag of plaster from eBay. I seem to recall that the first bag I bought was sold as "fine casting plaster", but this time I
didn't find any suitable-looking results for that search so I ended up buying "Plaster of Paris", which seems equivalent.</p>
<p>I stuffed up my first attempt at using this plaster by trying to add water to the plaster instead of the other way around. This resulted in thick clumps of
plaster that I couldn't mix into the water. But I'm not counting that as a discrete attempt.</p>
<p>I chucked away the wet clumpy mix and instead followed the instructions on the bag, adding 150g of powder to 200ml of water. This worked much better. I let the plaster
dry for a few hours, and then started the burnout cycle.</p>
<p>I found this burnout process from Pinterest in a DuckDuckGo image search:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3158"><img src="https://img.incoherency.co.uk/3158/thumb"></a></p>
<p>And programmed it into the <a href="https://incoherency.co.uk/blog/stories/process-controller.html">JPC-1000</a>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2363"><img src="https://img.incoherency.co.uk/2363/thumb"></a><br>
<small>(This is an old picture of the JPC-1000 for illustration. It still looks the same, but I've put the feet back on now so I don't need to stand the furnace on wooden blocks.)</small></p>
<p>The next morning, I took the mould out of the furnace and everything seemed to have worked as expected: the plastic was gone, but the plaster was still hard. Great success!</p>
<p>This is what the mould looked like before I poured the metal into it:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3166"><img src="https://img.incoherency.co.uk/3166/thumb"></a></p>
<p>The clamp is there to make it less likely to fall over and soak my trainers with aluminium, which I am keen to avoid, and the baking tray is there to contain any spillages,
for the same reason.</p>
<p>I set the furnace to 700&deg;C and chucked in a bunch of aluminium. The aluminium is offcuts of thin sheets that Emma is using to make
<a href="https://www.worryknot.co.uk/collections/spinner-necklace">spinner necklaces</a>. It is sold as "1050" grade, which I think is roughly elemental aluminium.
According to Wikipedia, it is "<a href="https://en.wikipedia.org/wiki/1050_aluminium_alloy">not used in castings</a>", lol. (I did not know this before, I just found out now).</p>
<p>I don't know how long you should leave the metal hot before pouring, so I just checked on the furnace periodically until the metal looked good and molten, and then poured it
into the mould pretty unceremoniously. It bubbled a bit for a few seconds as it was sitting in the mould, I assume this is air coming out (perhaps I should have added a 2nd
route for air to escape?).</p>
<p>After it had cooled for a decent while, I broke the mould apart and retrieved this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3144"><img src="https://img.incoherency.co.uk/3144/thumb"></a></p>
<p>It's not exactly what I was after, but it's pretty encouraging. I think there are only 2 major problems here:</p>
<p><ol>
<li>the small ring has not filled in at all: I expect the aluminium froze at the entry to this part of the mould before filling it, blocking it off</li>
<li>the large ring is not complete: I expect the aluminium shrunk as it cooled, which pulled the ring apart because there wasn't enough other material for it to draw in</li>
</ol></p>
<p><h2>Third attempt</h2></p>
<p>This time I added a solid part to the middle of each ring, in the hopes that it would allow metal to fill the ring faster and stop it from freezing at the entry, and that it would
also provide more material to draw in as the metal cools.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3165"><img src="https://img.incoherency.co.uk/3165/thumb"></a></p>
<p>I think my problem this time was that I didn't let the metal get hot enough. I again waited until it looked decently molten, but I think I need to make this more repeatable instead of just guessing.
It seemed a bit less runny as it was pouring, and after it cooled down I discovered that it had not worked very well at all:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3161"><img src="https://img.incoherency.co.uk/3161/thumb"></a></p>
<p>It looks like it froze almost immediately on contact with the mould, and did not allow any metal to flow into the mould.</p>
<p>So for next time I think I want to give the metal more time in the furnace to make sure it's properly up to temperature.
If you can offer any better ideas, please get in touch. I definitely need it.</p>
<p><h2>More</h2></p>
<p><h3>Vacuum casting</h3></p>
<p>Professional jewellers sometimes cast into a machine that applies a vacuum to the bottom of the mould. The plaster is apparently slightly porous, and the vacuum helps to suck
the metal into the mould. Here's a typical example from eBay:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3163"><img src="https://img.incoherency.co.uk/3163/thumb"></a></p>
<p>This is quite expensive, but I think I could build one quite cheaply. Here's a diagram from VegOilGuy's <a href="https://www.youtube.com/watch?v=qxj5eUkAFUI">video about lost PLA casting</a>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3162"><img src="https://img.incoherency.co.uk/3162/thumb"></a></p>
<p>This design uses a hand pump to suck the air out of a chamber underneath the mould, but I don't think that sounds appealing. I think an electric pump is a better idea.</p>
<p><h3>Centrifugal casting</h3></p>
<p>Another approach used in professional casting is to <a href="http://thelibraryofmanufacturing.com/centrifuge_casting.html">cast in a centrifuge</a>
so that the centrifugal force (<a href="https://en.wikipedia.org/wiki/Centrifugal_force">fight me</a>) pushes
the metal into the bottom of the mould. Here's a screen capture from <a href="https://www.youtube.com/watch?v=4HTuYa1BxEE">a demonstration video</a>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3164"><img src="https://img.incoherency.co.uk/3164/thumb"></a></p>
<p>These are also quite expensive, but I also think I could build one quite cheaply, although centrifugal casting has the downside that if something goes wrong
then it is liable to spray molten metal everywhere, which seems like it could be potentially hazardous. But I think it should produce much more force than a vacuum, so
is probably superior.</p>
<p>The way to test it would be to have it fling water into the bottom of the mould quite a few times: if you get wet, the machine is not ready for molten metal.</p>
<p><h3>Second furnace</h3></p>
<p>I think it would be better to have an electronically-controlled furnace for the burnout (like I have now), and also a separate furnace for melting the metal. That way the mould
can stay in the furnace right up until the time that the metal is poured, which would allow the mould to stay hot, and therefore make it less prone to prematurely freezing the
metal. I might be able to get some of this effect by just keeping the mould in the oven at 200&deg;C until I'm ready to use it.</p>
<p><h3>Excess metal</h3></p>
<p>So far I am pouring <i>significantly</i> more metal than goes into the rings. I sense that this will not be viable if I am working
with actual gold, as gold is expensive. If I need to buy 5x as much gold as the amount of gold in the rings, then I can't afford to do it, so I definitely need to work
on reducing the excess metal. But making rings <i>at all</i> is a more fundamental problem, so I'm starting with that one. The problem with reducing the amount of metal is that
it reduces the hydrostatic pressure at the bottom of the mould, which means it won't reproduce the detail of the mould as well.</p>
<p>Hydrostatic pressure wouldn't be a problem if casting in a centrifuge, so maybe a centrifuge is the way to go.</p>
<p><h3>Mystery alloys</h3></p>
<p>I would like to melt a bit of sentimentally-significant metal into the gold that we make our rings from. I'm aware that this would destroy the financial
value of the gold, but I still think it would be nice.</p>
<p>Most of the obvious candidate objects that I can think
of are made of either steel (which I can't usefully melt), or aluminium. Unfortunately, from what I've read, aluminium and gold do not alloy together, they instead form
a <a href="https://en.wikipedia.org/wiki/Gold%E2%80%93aluminium_intermetallic">gold-aluminium intermetallic</a>. What I want to know is if there is a low
concentration of aluminium at which they <i>do</i> alloy together.</p>
<p>I found this picture of "Aluminium aurate" from <a href="https://onyxmet.com/?route=product/product&product_id=2445">a place that sells it on purpose</a>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3159"><img src="https://img.incoherency.co.uk/3159/thumb"></a></p>
<p>And while it does look cool in its own way, powdery purple glitter is very much not the effect I'm after. But this is 21.5% aluminium. Maybe if it was only 1% aluminium
it would be fine?</p>
<p><h3>Keeping the mould in the flask</h3></p>
<p>The flask is made of stainless steel and expands in the furnace more than the plaster does. This means the plaster separates from the flask during the burnout, and
half the time when I try to take the mould out of the furnace the flask comes out and the mould stays inside. Perhaps I should try to punch some indentations into
it so that it keeps hold of the mould?
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/casting-rings.html</link>
   <guid>http://incoherency.co.uk/blog/stories/casting-rings.html</guid>
   <pubDate>Thu, 21 Jan 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Adventures in CPU design</title>
   <description><![CDATA[On Graham's recommendation, I recently bought an iCE40 FPGA and
have been learning a bit about how to use it. The iCE40 is good to get because there is good open-source tooling that supports it.
I was originally going to get the iCEstick evaluation board,
but there are other alternatives available more cheaply and with more logic elements. I ended up getting an iceFun
and have found it to be quite easy to use. The example projects are helpful.]]></description>
   <content:encoded><![CDATA[<p>On <a href="https://www.grahamedgecombe.com/">Graham</a>'s recommendation, I recently bought an iCE40 FPGA and
have been learning a bit about how to use it. The iCE40 is good to get because there is good open-source tooling that supports it.
I was originally going to get the <a href="http://www.latticesemi.com/icestick">iCEstick</a> evaluation board,
but there are other alternatives available more cheaply and with more logic elements. I ended up getting an <a href="https://www.robot-electronics.co.uk/icefun.html?SID=091505612007d8a829d084c896a19546">iceFun</a>
and have found it to be quite easy to use. The <a href="https://github.com/devantech/iceFUN">example projects</a> are helpful.</p>
<p>Playing with the FPGA has led to me designing <a href="https://github.com/jes/jescpu">a tiny CPU</a>, learning
a bit about CPU design (in that order, unfortunately), and rekindling an old desire to build a CPU out of logic chips.</p>
<p><h2>Some interesting DIY CPUs</h2></p>
<p><h3>Ben Eater breadboard CPU</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/3148"><img src="https://img.incoherency.co.uk/3148/thumb"></a>
<br><small>(Screenshot from <a href="https://www.youtube.com/watch?v=HyznrdDSSGM">a YouTube video</a>).</small></p>
<p>Ben Eater has a <a href="https://eater.net/8bit">tutorial</a>
in which he walks you through building an 8-bit CPU out of logic chips on breadboards.
It's a pretty primitive CPU, sporting only 4-bit addresses (!), but it does work and is the
most comprehensive tutorial I have found that doesn't resort to either FPGA or
simulation.</p>
<p><h3>Magic-1</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/2410"><img src="https://img.incoherency.co.uk/2410/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3149"><img src="https://img.incoherency.co.uk/3149/thumb"></a>
<br><small>(Pictures from <a href="http://www.homebrewcpu.com/photo_gallery.htm">the Magic-1 Photo Gallery</a>.)</small></p>
<p>I've been a fan of <a href="http://homebrewcpu.com/">Magic-1</a> for a long time.
It is the most technically-advanced DIY CPU that I am aware of (not counting FPGA designs). It has
16-bit addresses, but uses an MMU to map 4MB of physical memory into a 64K code segment and
64K data segment for each process. It also supports interrupts and memory protection,
and runs a port of Minix. Really an incredible project. And it's all done with only about 200
ICs, and uses <a href="https://en.wikipedia.org/wiki/Wire_wrap">wire-wrap construction</a> instead
of soldering.</p>
<p>It even has a working TCP/IP stack and you can telnet to it from anywhere on the Internet. I have
done so in the past but it appears to be down at the moment.</p>
<p><h3>Megaprocessor</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/3150"><img src="https://img.incoherency.co.uk/3150/thumb"></a>
<br>(Picture from <a href="http://www.computinghistory.org.uk/det/43063/The-Megaprocessor/">the Centre for Computing History</a>).</small></p>
<p>The <a href="http://www.megaprocessor.com/">Megaprocessor</a> is a CPU built almost entirely out of individual transistors.
Most of the transistors also feature an LED to indicate
their state.  It is enormous, I don't think the photograph really does it justice. It is on display at the <a href="http://www.computinghistory.org.uk/">Centre for Computing History</a>
in Cambridge, which is well worth a visit if you are interested in computing history. A lot of the computers in the museum
are working and running and you're able (and encouraged!) to interact with them.</p>
<p>Interestingly, the Megaprocessor features four general-purpose 16-bit registers and a 16-bit stack pointer. I think if it were down to me,
and I were manually building the entire CPU out of individual transistors, I might have foregone 1 or 2 of those registers, and made
the remaining ones a bit narrower. But it's a brilliant machine. Has to be seen to be believed.</p>
<p><h3>Using an EEPROM as an ALU</h3></p>
<p>I don't know of any examples of CPUs that do this, but it's interesting nonetheless, and I'm sure there are some out there somewhere.
<a href="http://6502.org/users/dieter/a1/a1_3.htm">The idea</a> is that EEPROMs are now large and cheap enough that
you can implement the ALU for an 8-bit CPU as lookup tables in EEPROMs. The "address" you look up is the concatenation
of the 2 operands, and the chip you select is based on the selected operation (e.g. one lookup table for addition, one for
bitwise AND, etc.).</p>
<p>I don't think I would go this route as it feels a bit wasteful. If you want to spend the transistor count of a bunch of 64K EEPROMs
on your ALU, there are much more interesting things you can do than a lookup table. It's a funny idea though.</p>
<p><h2>My first CPU</h2></p>
<p>I have implemented <a href="https://github.com/jes/jescpu">a basic CPU</a> in Verilog, to run on my
iCE40 FPGA. I actually had almost no idea what I was doing when I started this, I was just winging it and
learning as I went. And considering that there are not that many design decisions, there are quite a lot of bad design decisions.</p>
<p>It has an 8-bit address space, with 256 bytes of RAM synthesised directly on the FPGA, and all of the instructions
take direct memory addresses as arguments. There is no support for immediate mode arguments, or general-purpose registers,
or even indirect memory addresses. The reason I did this is that I thought it would keep things simple, and for the
VM simulating the CPU it did. My mental model of how a CPU works is basically the same as a program simulating the CPU,
which is why my first thought was to come up with an architecture that is easy to <i>simulate</i>, rather than one that
is easy to make in actual hardware.
Having written the
Verilog, I now accept that it would be simpler if the operations all worked directly on registers, and there were separate
load/store instructions to access memory. After all, the Verilog I wrote just loads values from memory into internal
registers anyway, so they may as well be exposed.</p>
<p>One problem with my architecture is that the only way to support pointers is with self-modifying code. For example if you want to work with the
value stored in the address stored in address 0x80, then you have to first load the value from address 0x80 into the operand of the
instruction in question, so that when that instruction executes it fetches its operand from the correct address.
It actually turns out to be not too hard to work with this once you've figured out the strategy, although
I have not yet written any complex programs with it.</p>
<p>Another problem is that it forces the CPU to waste cycles on memory read/write even if the next instruction is just going to be working
on the same values again.</p>
<p>I think a superior architecture would be to split up almost all of the separate "states" I have, and instead turn each state into an opcode:
instead of "load a value from memory into a register" being a <i>state</i>, that should just be the total effect of an instruction.
That way the programmer has more control over the work the CPU is doing, instead of having to select from a tiny array of available
opcodes and then watch the CPU stupidly storing at, and loading from, the same address over and over again.</p>
<p>The biggest problem with my CPU is that I don't fully understand some of the timing problems. I added a "wait" state that allows
it to waste some cycles while waiting to get data back from RAM, but I found that if I make it wait for between 2 and 22 cycles, then the CPU
sometimes gets into an illegal state and halts. I do not know why. If I only wait for 1 cycle then it always works, and if I wait for 23 or
more cycles, it always works.</p>
<p>(<b>Update 2021-01-15</b>: Graham pointed me to <a href="https://github.com/nmigen/nmigen/blob/master/nmigen/vendor/lattice_ice40.py#L350">a comment
in nmigen</a> which suggests there is a hardware bug in the iCE40 FPGAs that means block RAMs read all zeroes for the first 3 microseconds. Fun.
<a href="https://github.com/jes/jescpu/commit/b1efbeab5657a80c613afaa98df2028f10d28d4a">The solution</a> is to make the CPU sit idle when it first
starts up for long enough to let the RAM start working. The reason my CPU <i>sometimes</i> worked before is that opcode 0 is NOP! As
long as RAM was returning all zeroes, it would just sit and NOP forever. I think the problems arose in cases where it was trying to fetch
an instruction across the boundary of the memory starting to work. It would get a correct opcode, but an incorrect operand, which would
eventually lead to trying to execute an illegal instruction and halting.)</p>
<p><h2>Nand2Tetris</h2></p>
<p>Since working on my Verilog CPU, I have gone through the <a href="https://www.nand2tetris.org/">Nand2Tetris</a> part 1 course.
"Part 1" is hardware design and "part 2" is software design, I've only done part 1. The course is taught using a dedicated hardware-description language,
with a basic <a href="https://en.wikipedia.org/wiki/Swing_(Java)">Swing</a> GUI,
called "HDL". HDL differs from "real-life" hardware-description languages mainly in that it supports almost no syntactic sugar, which means
you are forced to understand everything from first principles. It has
a builtin NAND gate, and a builtin D-flip-flop, and you make everything else out of these primitives. (The course does explain that in
real life D-flip-flops can be made out of NAND gates, but the hardware simulator in the course does not support cycles in the graph of
gate connections, so D-flip-flops are provided as a special-case primitive).</p>
<p>
You start by making basic logic gates out of just NAND, then combine them together to make logic gates that operate on a bus (e.g. 16-bit AND),
then create multiplexers and demultiplexers, a half adder and full adder, an ALU, rewritable storage elements starting from a single bit and building
all the way up to a 16K-word RAM, and a memory implementation that includes the RAM and the memory-mapped IO.
The CPU itself is actually extremely simple once all of the supporting pieces are done.</p>
<p>Following the Nand2Tetris course gave me a much greater appreciation for what is going on when I write Verilog.</p>
<p>The course is meant to be accessible to someone who has no prior knowledge of computer science, so if you have prior knowledge
then you can skip over the parts of the lectures that you already know and just complete the exercises. I thoroughly recommend the course, I learnt a lot from
just doing the exercises, and watching the lectures on the parts I didn't understand.</p>
<p>The CPU they have you design uses a 16-bit address space with 16K-words of RAM, and then 8K-words of memory-mapped IO for the screen, and 1
word of memory-mapped IO for the keyboard. Each instruction is a single word, and there are 2 types of instruction: "A-instructions" load
an immediate 15-bit value into the A register, and "C-instructions" compute something using the ALU. Various bits in the opcode specify
where the 2 inputs come from, where the outputs go, how to operate the ALU, and whether to perform a conditional or unconditional jump.</p>
<p>The biggest revelation for me in Nand2Tetris was the design of the ALU. The core of the ALU is just a 16-bit adder, and a 16-bit bitwise
AND. There is a flag to select the function (add or AND), and there are flags to zero out each of the inputs, and invert the bits of each of the inputs, and a flag to invert the bits of the output. Unbelievably, using just
the adder, the bitwise AND, the 2 zero flags and the 3 negation flags, the ALU can compute quite a lot of different functions:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3151"><img src="https://img.incoherency.co.uk/3151/thumb"></a>
<br><small>(From <a href="https://b1391bd6-da3d-477d-8c01-38cdf774495a.filesusr.com/ugd/44046b_89c60703ebfc4bf39acef13bdc050f5d.pdf">the course textbook</a>).</small></p>
<p>I think this ALU (and the entire Nand2Tetris instruction set architecture) is really beautiful in its simplicity.</p>
<p>The only thing I didn't like about the Nand2Tetris CPU is that it uses the "Harvard architecture", i.e. it separates code and data. The code
is stored in a ROM, and there is no way to execute code in RAM, so this means the CPU is wholly incapable of creating and running new code.
You can't make a bootloader, and there is no chance of running any programs that you compile within the CPU, without going through some
external system to write them to the ROM. The reason they have done it this way is it means the CPU doesn't need an internal state machine: at each
cycle it gets a 16-bit instruction from the ROM and a 16-bit value from RAM, and can operate on them both simultaneously, without even having to toggle
between "fetch" and "execute" states.</p>
<p><h2>My next CPU</h2></p>
<p>I would like to design a simple CPU that I can create using discrete logic chips and use to run a CP/M-like OS. Although the ultimate
goal would be to physically build the CPU, I would start with an FPGA because that makes it a lot easier to iterate and debug.</p>
<p>It should be as simple as possible, while still able to run an OS. In all but the most extreme cases, I would rather trade off performance to
gain simplicity.
I think
I would probably want to support interrupts, but this might just be in the form of a single global interurpt handler, which
is then responsible for polling the attached devices to work out which one of them wants to do something. Not completely
sure on that.</p>
<p>I think I would save the bother of breadboarding or wire-wrapping, and get PCBs made in China.</p>
<p>I would abandon the memory-to-memory architecture of my first CPU design, in favour of a more traditional register-based architecture, and I would
almost certainly copy the Nand2Tetris ALU.</p>
<p>I would want the OS to be self-hosting, and I'd want it to be able to run a compiler for either C or a C-like high-level
language, although the OS itself would probably be written in assembly language. There are a decent handful of C compilers
available for CP/M, so it is clearly possible to run a C compiler in such an environment. Interestingly Magic-1 can not
run a C compiler, I'm not really sure why. The only way to compile C programs for Magic-1 is to cross-compile them from
a more capable machine.</p>
<p>(<b>Update 2021-01-31:</b> In Bill Buzbee's <a href="https://www.youtube.com/watch?v=qOcSnaK0yBw">latest video on Magic-1</a> he reveals
that it now compiles something called "Small C" natively. I expect this is a relative of <a href="https://github.com/DoctorWkt/smallc">this
smallc</a> compiler I found on github. I expect that might be worth trying to use for my CPU as well.)</p>
<p>I'd probably want a 16-bit address space, but I'm still undecided on whether I would want 8-bit or 16-bit words. 8-bit words probably result
in less circuitry required overall, but they do complicate the state machine of the CPU because addresses would have to be read in 2 separate
fetches from memory. Perhaps it might be funny to have an oddball word size that's not a multiple of 8.</p>
<p>In terms of the rest of the computer, I think I'd be looking for roughly RC2014-level capabilities. So I'd want a
serial console, a second serial port for other communication, and some sort of storage (probably either hard disk, CompactFlash, or SD).
Since I already know that this is what I want, I don't think it would be too hard to make it compatible with the RC2014 bus
so that in a lot of cases I could use unmodified RC2014 cards.</p>
<p>I don't think I would want to support bank switching. It seems like the RC2014's bank switching is rather wasted on
CP/M, as CP/M programs don't know how to use it. I think I'd aim to have a very small boot ROM that is permanently mapped
into the address space, and that just presents a basic boot monitor and loads the OS off the storage device.</p>
<p>I don't know how likely this project is to happen any time soon, but the idea of making my own CPU has intrigued me
ever since I first saw Magic-1, and I'm definitely now closer than ever to being able to make it happen.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/cpu-design.html</link>
   <guid>http://incoherency.co.uk/blog/stories/cpu-design.html</guid>
   <pubDate>Fri, 15 Jan 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Someone copied Stegoseed and deleted my name from it</title>
   <description><![CDATA[I searched DuckDuckGo for "stegoseed" earlier and was surprised to find that the top result was not
my stegoseed project, but was something else that seemed to do
a similar thing:]]></description>
   <content:encoded><![CDATA[<p>I searched DuckDuckGo for "stegoseed" earlier and was surprised to find that the top result was not
<a href="https://incoherency.co.uk/stegoseed/">my stegoseed project</a>, but was something else that seemed to do
a similar thing:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3131"><img src="https://img.incoherency.co.uk/3131/thumb"></a></p>
<p>(I wonder if I was the second result because the "Stegoseed" link in my navbar used to just say "Bitcoin Steganography", so it wasn't giving it enough
search engine link juice for "stegoseed"? I've changed it now).</p>
<p>Curious, I clicked through to the Groestlcoin tool (left) and was surprised to find that it looks quite similar to mine (right):</p>
<p><a class="img" href="https://img.incoherency.co.uk/3133"><img src="https://img.incoherency.co.uk/3133/thumb"></a></p>
<p>It has only 2 obvious differences:</p>
<p><ol>
<li>My name and the link to the <a href="https://incoherency.co.uk/blog/stories/steganographic-bitcoin-seeds.html">accompanying blog post</a> have been deleted</li>
<li>"Bitcoin" has been changed to say "groestlcoin"</li>
</ol></p>
<p>(<b>Update 2021-01-04</b>: The Groestlcoin Stegoseed page now states that it is a fork of my project).</p>
<p>I'd never heard of Groestlcoin before and initially I wondered if this was a scam to exfiltrate people's Bitcoin keys, but
I checked the source and there appear to be no changes at all, other than to the text. It turns out that "Groestlcoin" is
actually just an obscure altcoin.</p>
<p>I also found that lots of posts on the <a href="https://reddit.com/r/groestlcoin/">r/groestlcoin</a> subreddit are announcements of software
releases by the Groestlcoin "Development Team":</p>
<p><a class="img" href="https://img.incoherency.co.uk/3132"><img src="https://img.incoherency.co.uk/3132/thumb"></a></p>
<p>These are (almost?) all just copies of other pre-existing projects but with the text changed to say "Groestlcoin" instead of "Bitcoin",
and with the original authors' names deleted. This is typically done in a commit with commit message just saying "groestlize".</p>
<p>Here's a bunch of examples of Groestlcoin github projects that are derived from Bitcoin projects:</p>
<p><ul></p>
<p><li>
<a href="https://github.com/Groestlcoin/WalletWasabi/commit/e033f5fe4450bf771a4c98705123c6c13ac3f8f1">GroestlMix Wallet</a>
(derived from <a href="https://github.com/zkSNACKs/WalletWasabi">Wasabi Wallet</a> by <a href="https://github.com/zkSNACKs">zkSNACKs</a>):
"Bitcoin" changed to "Groestlcoin", "Wasabi" changed to "GroestlMix", CI labels deleted from <tt>README.md</tt>, signature verification instructions
deleted from <tt>README.md</tt>, some technical changes.
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/vanitygen/commit/5f6774ef2a281383d117b1a2af4b2baec831a3d6">vanitygen</a>
(derived from <a href="https://github.com/samr7/vanitygen">vanitygen</a> by <a href="https://github.com/samr7">samr7</a>):
"Bitcoin" changed to "Groestlcoin", some explanation deleted from <tt>README</tt>.
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/groestlcoinjs-lib/commit/d77138d8e64445c60d50283d91a7166ab6a582fa">groestlcoinjs-lib</a>
(derived from <a href="https://github.com/bitcoinjs/bitcoinjs-lib">bitcoinjs-lib</a> by <a href="https://github.com/bitcoinjs">bitcoinjs</a>):
"Bitcoin" changed to "Groestlcoin", CI labels deleted from <tt>README.md</tt>, "Altcoin-ready" text deleted, warning not to use this library in production deleted,
instructions for "Flow" deleted, "Contributors" and "Contributing" sections deleted, list of contributors deleted from <tt>package.json</tt> and replaced with
"Groestlcoin developers".
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/php-OP_RETURN/commit/03d700d7bd41d3f7c09cf8a422bde6a3ba6f7c94">php-OP_RETURN</a>
(derived from <a href="https://github.com/coinspark/php-OP_RETURN">php-OP_RETURN</a> by <a href="https://github.com/coinspark">CoinSpark</a>):
"Bitcoin" changed to "Groestlcoin", copyright notice deleted.
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/python-OP_RETURN/commit/e3c0164199ac885e07315784af60705b72bccc34">python-OP_RETURN</a>
(derived from <a href="https://github.com/coinspark/python-OP_RETURN">python-OP_RETURN</a> by <a href="https://github.com/coinspark">CoinSpark</a>):
"Bitcoin" changed to "Groestlcoin", copyright notice deleted.
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/crypto_bot/commit/18c9a210e2caad08a704c5b09dceb2b99c76d4dc">crypto_bot</a>
(derived from <a href="https://github.com/busterroni/crypto_bot">crypto_bot</a> by <a href="https://github.com/busterroni">busterroni</a>):
"Cryptocurrencies" changed to "Groestlcoin", donation address deleted, lots of stats deleted from the code (I guess they don't exist for Groestlcoin), reddit link
to "Message my creator" changed from u/busterroni to u/jackielove4u.
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/cryptoseed/commit/84e1e57d2ab09a6700ce1e448ba383bd259c4b75">GroestlSeed</a>
(derived from <a href="https://github.com/anderson-arlen/cryptoseed">cryptoseed</a> by <a href="https://github.com/anderson-arlen/">Arlen Anderson</a>):
"Bitcoin" changed to "Groestlcoin", "CryptoSeed" changed to "GroestlSeed", Bitcoin donation address deleted.
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/groestldice/commit/76571920289a55b71cf227dd822927b88ecca133">groestldice</a>
(derived from <a href="https://github.com/bitcoinfromscratch/bfs-dice">bfs-dice</a> by <a href="https://github.com/bitcoinfromscratch">bitcoinfromscratch</a>):
"Bitcoin" changed to "Groestlcoin", instructions for verifying signatures mostly deleted, author email address changed.
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/groestlcoin-live-transactions/commit/81e79c464985d6047aa07601d32f406e973510e1">groestlcoin-live-transactions</a>
(derived from <a href="https://github.com/guerrerocarlos/bitcoin-live-transactions">bitcoin-live-transactions</a> by <a href="https://github.com/guerrerocarlos">Carlos Guerrero</a>):
"Bitcoin" changed to "Groestlcoin", author email address changed.
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/big-spender/commit/e36e8fd5c33d632653a4c5d190aa59b2e22f1055">BigSpender</a>
(derived from <a href="https://github.com/ZenGo-X/big-spender">BigSpender</a> by <a href="https://github.com/ZenGo-X">ZenGo X</a>):
"Bitcoin" changed to "Groestlcoin", example GIF deleted, author email address changed.
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/seedguardian/commit/feea6deb6c99b861ad3f7797e1ce1b24c9c4ada7">seedguardian</a>
(derived from <a href="https://github.com/jasadams/seedguardian.github.io">seedguardian</a> by <a href="https://github.com/jasadams">Jason Adams</a>):
"Bitcoin" changed to "Groestlcoin", "Powered by Github Pages" changed to "Powered by Groestlcoin Developers", "Backlog" section deleted from <tt>readme.md</tt>, a warning
to "use with care" changed to "should be BIP39 compatible !", "(Alpha)" status labelling deleted.
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/emoji-wallet/commit/49b2ac934d84b8e66e6bd12a46c1b73241f28e63">emoji-wallet</a>
(derived from <a href="https://github.com/stepansnigirev/emoji-wallet">emoji-wallet</a> by <a href="https://github.com/stepansnigirev">Stepan Snigirev</a>):
"Bitcoin" changed to "Groestlcoin", and some actual technical changes.
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/build-bip39/commit/919c2c344904feb11a9f0223864aab21c0cded53">BIP39 Mnemonic Builder</a>
(derived from <a href="https://github.com/mikeygee/bip39">BIP39 Mnemonic Builder</a> by <a href="https://github.com/mikeygee">Mikey Gee</a>):
"Bitcoin" changed to "Groestlcoin", "Motivation" paragraphs deleted from <tt>README.md</tt>, icon changed.
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/groestlcoinjs-message/commit/4b2a54d25ff010f98c924e71eda37a7fef1d3523">groestlcoinjs-message</a>
(derived from <a href="https://github.com/bitcoinjs/bitcoinjs-message">bitcoinjs-message</a> by <a href="https://github.com/bitcoinjs">bitcoinjs</a>):
"Bitcoin" changed to "Groestlcoin", CI labels deleted from <tt>README.md</tt>, signature examples changed to just say "valid signature" instead of
showing the signature that is generated (presumably running the code to find out the real signatures was too much work).
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/genesis-block/commit/8e2b33c633ff4abea9a25196744513517d52e3fa">genesis-block</a>
(derived from <a href="https://github.com/nasa8x/genesis-block">genesis-block</a> by <a href="https://github.com/nasa8x">nasa8x</a>):
"Multiple Hash Algorithms" changed to "Groestlcoin", default value for timestamping text changed from "The Times 18/Jan/2018. Don't work for weekends, work for our goals." to "Pressure must be put on Vladimir Putin over Crimea".
</li></p>
<p><li>
<a href="https://github.com/Groestlcoin/corewatchpush/commit/ac858bab7d6a970c996d995523142b77b427cf76">CoreWatchPush</a>
(derived from <a href="https://github.com/jonasschnelli/corewatchpush">CoreWatchPush</a> by <a href="https://github.com/jonasschnelli">Jonas Schnelli</a>):
"Bitcoin" changed to "Groestlcoin".
</li></p>
<p></ul></p>
<p>That's not even all of them. I got fed up of looking through the commit history of the rest of the projects, you can <a href="https://github.com/Groestlcoin">find them here</a>.</p>
<p>Anyway, from what I can tell, Groestlcoin is mostly just Bitcoin but with names changed.</p>
<p><h2>Copying open source projects for fun and profit</h2></p>
<p>Obviously there's nothing inherently wrong with making open source projects derived from
other projects - indeed, this is half the point of open source in the first place. But deleting the original author's name leaves a bit of a bad taste in the mouth.</p>
<p>If you happen to want to create your own fringe altcoin, but you don't have any supporting projects, this is what seems to be
the formula for creating them:</p>
<p><ol>
<li>copy someone's Bitcoin-related project</li>
<li>change "Bitcoin" to "Groestlcoin"</li>
<li>delete any explanatory text that you don't understand</li>
<li>delete links to explanatory blog posts or related websites</li>
<li>delete the original author's name and any other references to the original author</li>
<li>delete any Bitcoin donation addresses</li>
<li>???</li>
<li>profit</li>
</ol></p>
<p>Importantly, make sure no credit is given to anyone outside the Groestlcoin project. Even change "Powered by Github Pages" to
<a href="https://github.com/Groestlcoin/seedguardian/commit/feea6deb6c99b861ad3f7797e1ce1b24c9c4ada7#diff-0eb547304658805aad788d320f10bf1f292797b5e6d745a3bf617584da017051L175">"Powered by Groestlcoin Developers"</a> if you have to.</p>
<p>Oh, and make sure you have "Issues" disabled on your github repo so that the original authors can't come
in and request that you add their names back. </p>
<p><h2>What do I think Groestlcoin should do?</h2></p>
<p>Simply writing "This project is derived from X project by Y author" would be a substantial improvement.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/groestlcoin.html</link>
   <guid>http://incoherency.co.uk/blog/stories/groestlcoin.html</guid>
   <pubDate>Sun, 03 Jan 2021 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I wrote a semi-literate brainfuck compiler for CP/M</title>
   <description><![CDATA[Literate Programming is
"a programming paradigm introduced by Donald Knuth in which a computer program is given an
explanation of its logic in a natural language". It's something I've wanted to have a go
at for a while but never got around to. Yesterday, for fun, I wrote a brainfuck compiler for the
RC2014 and it seemed like a good fit for Literate Programming
because it's short enough to get my feet wet
but has enough detail that there is some interesting stuff to explain.]]></description>
   <content:encoded><![CDATA[<p><a href="https://en.wikipedia.org/wiki/Literate_programming">Literate Programming</a> is
"a programming paradigm introduced by Donald Knuth in which a computer program is given an
explanation of its logic in a natural language". It's something I've wanted to have a go
at for a while but never got around to. Yesterday, for fun, I wrote a brainfuck compiler for the
<a href="https://incoherency.co.uk/blog/tags/rc2014.html">RC2014</a> and it seemed like a good fit for Literate Programming
because it's short enough to get my feet wet
but has enough detail that there is some interesting stuff to explain.</p>
<p>(I understand that typically special tooling
is used to facilitate the natural language component. I instead opted to write the natural
language component in the form of comments within the source file, and then translated the
commented source file into this blog post. This is why I call it only "semi-literate".)</p>
<p>I found that it took longer to write the explanation than it took to write the program,
so I probably won't be trying Literate Programming again any time soon, although I do admit
that it resulted in better code than I would have settled for if I didn't have to justify myself.</p>
<p>The concatenation of the code blocks in this post constitutes a complete working C program. If for
whatever reason you
don't feel like copy-and-pasting all the code blocks together into a working program, you can get it
in <a href="https://github.com/jes/cpm-brainfuck/blob/master/bfc.c">fully-commented C source form</a>
instead.</p>
<p>(<b>Update 2020-01-02</b>: <a href="https://www.grahamedgecombe.com/">Graham</a> showed me the
Wikipedia article describing the <a href="https://en.wikipedia.org/wiki/Zero_page_(CP/M)">CP/M Zero page</a>,
and pointed out that the base address of the BDOS is available in address 0x0006. I have now updated
the program on github so that it zeroes out all of the available memory up to the BDOS instead of only 30000 bytes.
The text in this blog post is still the original version because updating it is a hassle).</p>
<p>The best reference for the Z80 instruction set that I'm aware of is the
<a href="https://clrhome.org/table/">clrhome Z80 instruction set table</a>.
You might also benefit from reading the <a href="http://www.gaby.de/cpm/manuals/archive/cpm22htm/ch5.htm">System Interface section of the CP/M manual</a>.</p>
<p>Without further ado, I present:</p>
<p><hr></p>
<p><!-- lol, is it ok to put this in the body? my static site generator sux -->
<link rel="stylesheet" type="text/css" href="highlight.min.css">
<style>
pre { padding: 0; background: none; }
td { padding: 5px; text-align: center; }
</style></p>
<p><h2>A Semi-literate Brainfuck Compiler for CP/M</h2></p>
<p>The compiler itself should be relatively portable, although the generated
code squarely targets CP/M. I think it only generates 8080 code (a subset of
Z80) but I have
not tested it on anything other than a Z80.</p>
<p>Compile it within CP/M using the HI-TECH C Compiler:<br>
<tt>C>C -V E:BFC.C</tt></p>
<p>Then you can compile a Brainfuck program:<br>
<tt>C>BFC E:HELLO.BF</tt></p>
<p>And then you can execute the generated program written to <tt>E:HELLO.COM</tt>:<br>
<tt>C>E:HELLO</tt></p>
<p>This is my first attempt at anything resembling literate programming. I
hope you enjoy.</p>
<p><pre><code class="c">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;</code></pre></p>
<p>We use a compile-time stack to store branch targets for loops.</p>
<p>1024 elements of stack space is quite generous, but we don't want the memory
for anything else so it doesn't hurt.</p>
<p><pre><code class="c">#define STACKSZ 1024
 
unsigned int *stack; /* stack for loop branch targets   */
int sp;              /* index for next push on to stack */</code></pre></p>
<p>30000 bytes of program memory is typical for Brainfuck interpreters.</p>
<p>The address space layout for the generated program will look like this:</p>
<p><table border>
<tr><td>0x00 - 0xff</td><td>code (unknown length)</td><td>memory (30000 bytes)</td><td>... gap ...</td><td colspan="3">unknown - 0xffff</td></tr>
<tr><td>Low storage</td><td colspan="3">Transient Program Area</td><td>CCP</td><td>BDOS</td><td>BIOS</td></tr>
</table></p>
<p>I wanted to offer all of the available memory in the Transient Program Area,
up to the start of the CCP, and while older versions of CP/M appeared to
offer a BDOS call which would report the base address of the CCP, there is
no such call available in CP/M 2.2 as far as I can tell, so we just stick
with the standard 30K bytes.</p>
<p>There is no bounds-checking on memory accesses, so in principle the entire
TPA <i>is</i> available to the generated program, but cells past 30000 will not
be zeroed in the preamble.</p>
<p><pre><code class="c">#define MEMSZ 30000
 
FILE *src_fp; /* Program source code file pointer        */
int src_char; /* The next character read from the source */
int src_eof;  /* Set to 1 when EOF is reached            */
 
char *prog;    /* Generated code goes in here              */
int prog_size; /* The allocated size for the "prog" buffer */
int prog_idx;  /* The index for the next output byte       */</code></pre></p>
<p><h2>File I/O</h2></p>
<p>The file is read 1 byte at a time by the tokeniser, so to "load" the source
code we just open the specified file in <tt>src_fp</tt>, and set <tt>src_char</tt>/<tt>src_eof</tt> to
indicate the current state.</p>
<p><pre><code class="c">void load(char *f) {
    src_fp = fopen(f, "r");
    if (!src_fp) {
        fprintf(stderr, "error: can't read %s\n", f);
        exit(1);
    }
    src_char = -1;
    src_eof = 0;
}</code></pre></p>
<p>To save the generated program, a single <tt>fwrite()</tt> call is sufficient.</p>
<p>The file is opened in <tt>"wb"</tt> (write, binary) mode so that CP/M will not insert
<tt>0x0d</tt> bytes before any <tt>0x0a</tt> in the output file.</p>
<p><pre><code class="c">void save(char *f) {
    FILE *fp;
    int wrote;
    if (!(fp = fopen(f, "wb"))) {
        fprintf(stderr, "error: can't write %s\n", f);
        exit(1);
    }
    wrote = fwrite(prog, 1, prog_size, fp);
    if (wrote != prog_size) {
        fprintf(stderr, "error: failed to write full output (only wrote %d of %d bytes)\n", wrote, prog_size);
        exit(1);
    }
    fclose(fp);
}</code></pre></p>
<p><h2>Code generation</h2></p>
<p>Code generation is centred around emitting bytes into the output program.
We do this by first resizing the <tt>prog</tt> buffer if necessary, and then sticking
the new byte in it.</p>
<p>A <tt>'+'</tt> is output to the console every time the buffer is reallocated, as a
basic progress indicator.</p>
<p><pre><code class="c">void emit(char c) {
    if (prog_idx &gt;= prog_size) {
        prog_size += 128;
        prog = realloc(prog, prog_size);
        putchar('+');
    }
    prog[prog_idx++] = c;
}</code></pre></p>
<p>The preamble goes at the very start of our generated program. It first
zeroes out 30K bytes of RAM starting at the end of the generated code,
and then initialises the memory pointer (stored in the <tt>hl</tt> register pair) to
point to the start of this block of 30K bytes.</p>
<p>We can't yet generate bytes for <tt>$prog_size</tt> because we don't know how large
the program will end up being, so we emit 0s for now, which will be
corrected later.</p>
<p><pre><code class="c">void emit_preamble() {
    emit(0x21); emit(0); emit(0);                 /* ld hl, $prog_size */
    emit(0x11); emit(MEMSZ&amp;0xff); emit(MEMSZ&gt;&gt;8); /* ld de, $MEMSZ     */
    emit(0x36); emit(0);                          /* loop: ld (hl), 0  */
    emit(0x23);                                   /* inc hl            */
    emit(0x1b);                                   /* dec de            */
    emit(0x7a);                                   /* ld a, d           */
    emit(0xb3);                                   /* or e              */
    emit(0xc2); emit(6); emit(1);                 /* jp nz, loop       */
    emit(0x21); emit(0); emit(0);                 /* ld hl, $prog_size */
}</code></pre></p>
<p>The postamble goes at the very end of our generated program. All it does
is jump to address 0 which returns control to the CCP.</p>
<p>Having written the "<tt>jp 0</tt>" instruction, we can now patch in the correct
values for <tt>$prog_size</tt> in the preamble.</p>
<p>The high byte of <tt>$prog_size</tt> (second byte because the Z80 is little-endian)
gets 1 added to it because the program will be loaded into address <tt>0x100</tt>,
which means all addresses are <tt>0x100</tt> larger than their corresponding
index in <tt>prog[]</tt>. We'll see this again later when generating branch target
addresses for loops.</p>
<p><pre><code class="c">void emit_postamble() {
    emit(0xc3); emit(0); emit(0); /* jp 0 */
    prog[1] = prog_size&amp;0xff;
    prog[2] = 1+(prog_size&gt;&gt;8);
    prog[16] = prog_size&amp;0xff;
    prog[17] = 1+(prog_size&gt;&gt;8);
}</code></pre></p>
<p>We use BDOS call number 1 to request a byte of input from the console.
This blocks until a byte is available.</p>
<p>The BDOS call is made by putting the number 1 in register <tt>c</tt> and calling
address 5. We push the <tt>hl</tt> register pair before, and pop it after, the
BDOS call because it gets clobbered by the BDOS.</p>
<p>The BDOS returns the input character in register <tt>a</tt>.</p>
<p>In the event that we received a <tt>'\r'</tt>, we throw it away and ask for another
byte, because CP/M gives us <tt>'\r\n'</tt> line endings and Brainfuck expects just
<tt>'\n'</tt>.</p>
<p><pre><code class="c">void emit_input() {
    emit(0x0e); emit(1);          /* ld c, 1           */
    emit(0xe5);                   /* push hl           */
    emit(0xcd); emit(5); emit(0); /* call 5            */
    emit(0xe1);                   /* pop hl            */
    emit(0xfe); emit('\r');       /* cp '\r'           */
    emit(0x20); emit(9);          /* jr nz, label      */
    emit(0x0e); emit(1);          /* ld c, 1           */
    emit(0xe5);                   /* push hl           */
    emit(0xcd); emit(5); emit(0); /* call 5            */
    emit(0xe1);                   /* pop hl            */
    emit(0x77);                   /* label: ld (hl), a */
}</code></pre></p>
<p>We use BDOS call number 2 to write a byte to the console.</p>
<p>To make the BDOS call we put number 2 in register <tt>c</tt> and the byte to write
in register <tt>e</tt> and then call address 5. Again we push <tt>hl</tt> before, and pop it
after, the BDOS call because it gets clobbered.</p>
<p>In the event that the program tries to write a <tt>'\n'</tt>, we make sure to first
write a <tt>'\r'</tt> so that the carriage is returned to the start of the line.</p>
<p><pre><code class="c">void emit_output() {
    emit(0x7e);                   /* ld a, (hl)        */
    emit(0xfe); emit('\n');       /* cp '\n'           */
    emit(0x20); emit(9);          /* jr nz, label      */
    emit(0x1e); emit('\r');       /* ld e, '\r'        */
    emit(0x0e); emit(2);          /* ld c, 2           */
    emit(0xe5);                   /* push hl           */
    emit(0xcd); emit(5); emit(0); /* call 5            */
    emit(0xe1);                   /* pop hl            */
    emit(0x5e);                   /* label: ld e, (hl) */
    emit(0x0e); emit(2);          /* ld c, 2           */
    emit(0xe5);                   /* push hl           */
    emit(0xcd); emit(5); emit(0); /* call 5            */
    emit(0xe1);                   /* pop hl            */
}</code></pre></p>
<p>"<tt>+</tt>" and "<tt>-</tt>" are implemented in terms of <tt>emit_add()</tt>.</p>
<p>We support changing the value of the cell by more than 1 at a time in
the interest of efficiency, although empirically this does not make as much
of an impact as I had hoped.</p>
<p>As a micro-optimisation, we revert to "<tt>inc (hl)</tt>" and "<tt>dec (hl)</tt>" when only
changing the value by 1, because these execute in 11 clock cycles, compared
to the 21 cycles required for arbitrary addition.</p>
<p><pre><code class="c">void emit_add(unsigned char n) {
    if (n == 1) {
        emit(0x34);          /* inc (hl)   */
    } else if (n == 0xff) {
        emit(0x35);          /* dec (hl)   */
    } else if (n != 0) {
        emit(0x7e);          /* ld a, (hl) */
        emit(0xc6); emit(n); /* add a, $n  */
        emit(0x77);          /* ld (hl), a */
    }
}</code></pre></p>
<p>"<tt>&gt;</tt>" and "<tt>&lt;</tt>" are implemented in terms of <tt>emit_right()</tt>.</p>
<p>Again we support changing the memory pointer by more than 1 at a time.</p>
<p>As a micro-optimisation, we revert to "<tt>inc hl</tt>" and "<tt>dec hl</tt>" when changing
the value by 3 or less because these execute in only 6 clock cycles,
compared to 21 cycles for arbitrary changes.</p>
<p><pre><code class="c">void emit_right(int n) {
    if (n &gt;= -3 &amp;&amp; n &lt; 0) {
        while (n++) emit(0x2b);               /* dec hl     */
    } else if (n &lt;= 3 &amp;&amp; n &gt; 0) {
        while (n--) emit(0x23);               /* inc hl     */
    } else if (n != 0) {
        emit(0x01); emit(n&amp;0xff); emit(n&gt;&gt;8); /* ld bc, $n  */
        emit(0x09);                           /* add hl, bc */
    }
}</code></pre></p>
<p>"<tt>[</tt>": When entering a loop we push the current output location onto the stack
before emitting the loop start code.</p>
<p>"<tt>or a</tt>" is used to set the condition flags based on the contents of the <tt>a</tt>
register.</p>
<p>We can't set the branch target address because we don't know it yet. This
will be filled in when the code for the matching "<tt>]</tt>" is generated.</p>
<p><pre><code class="c">void emit_loopstart() {
    stack[sp++] = prog_idx;
    if (sp &gt;= STACKSZ) {
        fprintf(stderr, "error: stack overflow\n");
        exit(1);
    }
    emit(0x7e);                   /* ld a, (hl)    */
    emit(0xb7);                   /* or a          */
    emit(0xca); emit(0); emit(0); /* jp z, $target */
}</code></pre></p>
<p>"<tt>]</tt>": Pop the address of the matching "<tt>[</tt>" off the stack and generate code to
jump there.</p>
<p>Modify the loop start code to set the correct branch target address for
when the loop exits.</p>
<p>Notice that all of the branch targets have 1 added to their (little-endian)
high byte. This is because the code is loaded at <tt>0x100</tt> when executing.</p>
<p><pre><code class="c">void emit_loopend() {
    int target;
    if (sp &lt;= 0) {
        fprintf(stderr, "error: stack undeflow\n");
        exit(1);
    }
    target = stack[--sp];
    emit(0xc3); emit(target&amp;0xff); emit(1+(target&gt;&gt;8)); /* jp $target */ 
    prog[target+3] = prog_idx&amp;0xff;
    prog[target+4] = 1+(prog_idx&gt;&gt;8);
}</code></pre></p>
<p><h2>Tokeniser</h2></p>
<p><tt>peek()</tt> returns the next byte from the source file, reading it using <tt>fgetc()</tt>
if necessary.</p>
<p>This is the only place that actually touches the file, and is also what
sets <tt>src_eof</tt> when <tt>EOF</tt> is encountered.</p>
<p><pre><code class="c">int peek() {
    if (src_char == -1) {
        src_char = fgetc(src_fp);
        if (src_char == EOF) src_eof = 1;
    }
    return src_char;
}</code></pre></p>
<p>To throw away the next byte from the file we just set <tt>src_char = -1</tt> so that
<tt>peek()</tt> gives us the next byte next time.</p>
<p><pre><code class="c">void discard() {
    src_char = -1;
}</code></pre></p>
<p>Check whether the next byte from the file is any one of the bytes in the "<tt>s</tt>"
string. It is used to tell when the next byte is not a Brainfuck character
so that it can be skipped over.</p>
<p><pre><code class="c">int peek_oneof(char *s) {
    for (; *s; s++)
        if (peek() == *s)
            return 1;
    return 0;
}</code></pre></p>
<p>Check if the next character is as specified, and if so consume it from the
input and return 1.</p>
<p><pre><code class="c">int consume(char c) {
    if (peek() == c) {
        discard();
        return 1;
    }
    return 0;
}</code></pre></p>
<p><h2>Main</h2></p>
<p><pre><code class="c">int main(int argc, char **argv) {
    int nright, i;
    unsigned char nadd;
    char *output_name;
 
    if (argc != 2) {
        fprintf(stderr, "usage: BFC FOO.BF\n");
        exit(1);
    }</code></pre></p>
<p>Let's generate the output filename.</p>
<p>In the worst case (<tt>argv[1]</tt> has no dot in it), we need to add 4 bytes to
its length (<tt>".COM"</tt>) plus a trailing nul byte.</p>
<p><pre><code class="c">    output_name = malloc(strlen(argv[1]) + 5);
    strcpy(output_name, argv[1]);</code></pre></p>
<p>Now find the final <tt>'.'</tt> in the filename (if any) and change the extension
to <tt>".COM"</tt>.</p>
<p>On CP/M there can only be one <tt>'.'</tt> character, but it doesn't hurt to stay
portable.</p>
<p><pre><code class="c">    for (i = strlen(output_name)-1; i&gt;0 &amp;&amp; output_name[i]!='.'; i--);
    if (i)
        output_name[i] = '\0';
    strcat(output_name, ".COM");</code></pre></p>
<p>Allocate the stack, load the source file, and emit the preamble code.</p>
<p><pre><code class="c">    stack = malloc(sizeof(int) * STACKSZ);
    load(argv[1]);
    emit_preamble();</code></pre></p>
<p>Loop until we've reached <tt>EOF</tt> on the source code file.</p>
<p><pre><code class="c">    while (!src_eof) {
        /* We count the number of consecutive "+" or "-" operators and
           emit_add() accordingly.
 
           emit_add() generates no code when nadd == 0. */
        nadd = 0;
        while (consume('+')) nadd++;
        while (consume('-')) nadd--;
        emit_add(nadd);
 
        /* Similarly, we count the number of consecutive "&gt;" or "&lt;" operators
           and emit_right() accordingly.
 
           emit_right() also generates no code when nright == 0. */
        nright = 0;
        while (consume('&gt;')) nright++;
        while (consume('&lt;')) nright--;
        emit_right(nright);
 
        /* Other operators are more straightforward. */
        if (consume('.')) emit_output();
        if (consume(',')) emit_input();
        if (consume('[')) emit_loopstart();
        if (consume(']')) emit_loopend();
 
        /* Finally we skip over any non-Brainfuck characters that happen to be
           present in the program source code. */
        while (!src_eof &amp;&amp; !peek_oneof("+-&gt;&lt;.,[]"))
            discard();
    }</code></pre></p>
<p>Emit the postamble code, save the generated code to the output file,
and print a <tt>'\n'</tt> to terminate the <tt>"++++++++++"</tt> on the console.</p>
<p><pre><code class="c">    emit_postamble();
    save(output_name);
    putchar('\n');</code></pre></p>
<p>All done, great success.</p>
<p><pre><code class="c">    return 0;
}</code></pre></p>
<p><script src="highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/literate-brainfuck.html</link>
   <guid>http://incoherency.co.uk/blog/stories/literate-brainfuck.html</guid>
   <pubDate>Tue, 29 Dec 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to copy files to/from the RC2014 using XMODEM</title>
   <description><![CDATA[Every time I get the RC2014 out and try to copy files to/from it,
I have to relearn how to do it, so I thought it best to document what I have found to be the easiest way.]]></description>
   <content:encoded><![CDATA[<p>Every time I get the <a href="https://incoherency.co.uk/blog/tags/rc2014.html">RC2014</a> out and try to copy files to/from it,
I have to relearn how to do it, so I thought it best to document what I have found to be the easiest way.</p>
<p>The <tt>rx</tt> and <tt>sx</tt> programs are provided by the <tt>lrzsz</tt> package on Ubuntu:</p>
<p><pre><code>$ sudo apt install lrzsz</code></pre></p>
<p>The first thing you need to do is use <tt>stty</tt> to enable RTS/CTS handshaking (I don't really understand why, it's just magic) and set the baud rate:</p>
<p><pre><code>$ stty -F /dev/ttyUSB0 115200 crtscts</code></pre></p>
<p>Without this everything will just hang and you'll have no idea why it's not working. You need to re-run this every time you plug in the USB FTDI cable.</p>
<p><h2>From Linux to CP/M</h2></p>
<p>We'll send <tt>foo.txt</tt> from Linux to <tt>A:FOO.TXT</tt> on CP/M. When sending from Linux to CP/M I find you need to start the
sending side before the receiving side otherwise it just hangs.</p>
<p>On Linux:</p>
<p><pre><code>$ sx foo.txt &lt; /dev/ttyUSB0 &gt; /dev/ttyUSB0</code></pre></p>
<p><tt>sx</tt> seems to stand for "send with xmodem". </p>
<p>On CP/M:</p>
<p><pre><code>B&gt;XMODEM A:FOO.TXT /R /X1</code></pre></p>
<p><tt>/R</tt> means "receive", and <tt>/X1</tt> means to communicate via CP/M's "reader and punch", i.e.
the secondary serial port.</p>
<p><h2>From CP/M to Linux</h2></p>
<p>We'll send <tt>A:FOO.TXT</tt> from CP/M to <tt>foo.txt</tt> on Linux. When sending from CP/M to Linux it doesn't seem to matter
whether you start the sending side or the receiving side first.</p>
<p>On Linux:</p>
<p><pre><code>$ rx foo.txt &lt; /dev/ttyUSB0 &gt; /dev/ttyUSB0</code></pre></p>
<p><tt>rx</tt> seems to stand for "receive with xmodem". </p>
<p>On CP/M:</p>
<p><pre><code>B&gt;XMODEM A:FOO.TXT /S /X1</code></pre></p>
<p><tt>/S</tt> means "send".</p>
<p><h2>Other notes</h2></p>
<p><h4>USB serial port permissions</h4></p>
<p>On my system, <tt>/dev/ttyUSB0</tt> becomes group-owned by <tt>dialout</tt>, so to access it you either
need to be in the <tt>dialout</tt> group, or just be root.</p>
<p><h4>Connecting to the RC2014</h4></p>
<p>Using a USB FTDI cable, connect the Linux machine to the RC2014's secondary serial port.
On <a href="https://incoherency.co.uk/blog/stories/rc2014-frontpanel.html">my machine</a> this is exposed with a 6-pin header on the back panel:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3117"><img src="https://img.incoherency.co.uk/3117/thumb"></a></p>
<p>But on a bare RC2014 it is this one:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3118"><img src="https://img.incoherency.co.uk/3118/thumb"></a></p>
<p><h4>XM.COM vs XMODEM.COM</h4></p>
<p>The <a href="https://github.com/wwarthen/RomWBW">RomWBW</a> CP/M image that is included on the CompactFlash card
contains a program called <tt>XMODEM.COM</tt> and a program called <tt>XM.COM</tt>. They both
appear to implement XMODEM, but <tt>XMODEM.COM</tt> is the one to use. I couldn't work out how to use <tt>XM.COM</tt>.</p>
<p><h4>Drive letter assignment</h4></p>
<p>Drive <tt>A:</tt> is a ramdisk, so files written here will be lost across a power cycle.</p>
<p>Drive <tt>B:</tt> is a romdisk, so you can't write files here.</p>
<p>The rest of the drives are backed by the CompactFlash card.</p>
<p><h4>CP/M file lengths</h4></p>
<p>CP/M doesn't actually have a way to know exact file lengths, it just knows how many blocks a file takes up,
which are 128 bytes long. This isn't a problem when transferring from Linux to CP/M, but text files transferred
from CP/M to Linux will be padded to a multiple of 128 bytes with <tt>^Z</tt> characters.</p>
<p><h4>Example output</h4></p>
<p>Linux:</p>
<p><pre><code>$ rx foo.txt &lt; /dev/ttyUSB0 &gt; /dev/ttyUSB0
  
rx: ready to receive foo.txt
Bytes received:     128   BPS:121                   
  
Transfer complete</code></pre></p>
<p>CP/M:</p>
<p><pre><code>B>XMODEM A:FOO.TXT /S /X1
 
File open
Sending via RDR/PUN with checksums
*
OK
Sent 1 blocks</code></pre>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/rc2014-xmodem.html</link>
   <guid>http://incoherency.co.uk/blog/stories/rc2014-xmodem.html</guid>
   <pubDate>Mon, 28 Dec 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>My Advent of Code Story</title>
   <description><![CDATA[4.40am. The alarm wakes me up, but I was pretty much awake already. I get out of bed, put on my dressing gown, make a cup of tea,
and sit down at the computer. I warm up my fingers with a few rounds of 10fastfingers.
I open up vim and type out my template: #!/usr/bin/perl, use strict; use warnings; while (&lt;&gt;) { chomp; }. I drink a sip of the tea and wait for
the clock to tick down. 4:59:40. Almost time. My heart races. 4:59:55. I hover the mouse cursor over the number 22. 4:59:58.
Why is time passing so slowly? The wait is agonising. 5:00:00. Finally. I click the left mouse button and off we go. Day 22 part 1: Crab Combat. The next 4 minutes and 58 seconds
pass in a furious blur of reading, thinking, and typing. I submit my answer. 158th place. Gah, close. On to part 2. More reading, thinking, coding, debugging, until
at 5:22:55 I submit my part 2 answer. 139th place. 0 points. Better luck next time. I browse Hacker News and /r/adventofcode
for half an hour while the adrenaline wears off, and then go back to bed.]]></description>
   <content:encoded><![CDATA[<p>4.40am. The alarm wakes me up, but I was pretty much awake already. I get out of bed, put on my dressing gown, make a cup of tea,
and sit down at the computer. I warm up my fingers with a few rounds of <a href="https://10fastfingers.com/">10fastfingers</a>.
I open up vim and type out my template: <tt>#!/usr/bin/perl</tt>, <tt>use strict; use warnings; while (&lt;&gt;) { chomp; }</tt>. I drink a sip of the tea and wait for
the clock to tick down. 4:59:40. Almost time. My heart races. 4:59:55. I hover the mouse cursor over the number 22. 4:59:58.
Why is time passing so slowly? The wait is agonising. 5:00:00. Finally. I click the left mouse button and off we go. Day 22 part 1: <a href="https://adventofcode.com/2020/day/22">Crab Combat</a>. The next 4 minutes and 58 seconds
pass in a furious blur of reading, thinking, and typing. I submit my answer. 158th place. Gah, close. On to part 2. More reading, thinking, coding, debugging, until
at 5:22:55 I submit my part 2 answer. 139th place. 0 points. Better luck next time. I browse Hacker News and <a href="https://old.reddit.com/r/adventofcode">/r/adventofcode</a>
for half an hour while the adrenaline wears off, and then go back to bed.</p>
<p>This has roughly been my routine for the past 25 days. I've been competing in <a href="https://adventofcode.com/">Advent of Code</a>, which is
an annual advent calendar of small programming puzzles. Each puzzle is released at midnight EST, which is 5am GMT. Each puzzle (except day 25) consists of 2 parts, but
you don't get to see what the second part is until after you've solved the first.</p>
<p>Advent of Code's creator, <a href="http://was.tl/">Eric Wastl</a>, says that it's not strictly a programming competition,
that it merely has just enough affordances that those who want to treat it like a programming competition can do so. Specifically, the first 100
people to solve a part 1 or a part 2 receive points based on their rank: 1st gets 100 points down to 100th who gets 1 point. The <a href="https://adventofcode.com/2020/leaderboard">overall
leaderboard</a> shows the points and ranks of the top 100 participants.</p>
<p>According to the <a href="https://adventofcode.com/2020/stats">stats page</a> over 155,000 people have submitted a correct solution to
day 1 part 1, although obviously the vast majority are not treating it as a competition.</p>
<p><h2>Results</h2></p>
<p>I did some of Advent of Code last year, but didn't start until day 12 and didn't reliably get up at 5am to do it. I ranked on the daily leaderboards a couple of times,
which was exciting, but really
I was only doing it for fun. This year I started out only trying to beat my friends, but after a 10th place on day 6 part 1, and points scored for both parts of day 7,
I was sitting 54th on the overall leaderboard! 46th place on day 8 part 2 bumped me up 2 more places, to 52nd overall, and from there I started taking the
competition quite seriously.</p>
<p>Then followed a bit of a dry spell, and after day 13 I was sitting in 96th place, only 12 points away from dropping off the leaderboard. Day 14 was
my best day of the competition, scoring 165 points with 13th on part 1 and 24th on part 2. Back up to 66th place. Phew! Safe again, for now.</p>
<p>After day 19 I was down to 94th place, but 29th on day 20 part 2 bumped me back up to 83rd. 0 points on day 21, I dropped to 85th. 0 points on day 22,
I dropped to 88th. On day 23 I scraped 11 points from 90th place on part 1, but still dropped down to 90th overall. 0 points on day 24, I dropped to 96th place.
And finally I scored 0 points on day 25, finishing the competition with 585 points and <b>103rd place</b>.</p>
<p>Although I had a lot of fun during the competition, this ending was a pretty crushing defeat. After 18 straight days in the top 100 on the overall leaderboard,
I was now permanently off the 2020 leaderboard. Just another one of the 155,000 who don't get their name in lights.</p>
<p>The person in 100th place on the leaderboard scored 588 points, only 3 more than me. I worked out that if I had solved days 7 and 8 one second faster, and day 6 three seconds faster, then I would have 
bagged the 4 extra points to take 100th place. My defeat came down to just 5 seconds of programming time.</p>
<p>Obviously, from a certain perspective, 103rd place in a global programming competition with arguably 155,000 entrants is a great success, but I can't help feeling
an enormous sense of loss from missing out on the overall leaderboard by so little, and falling off it on the very last day.</p>
<p>I probably won't be doing Advent of Code again next year, because getting up in time for 5am every day is very annoying (although this is made easier by the fact that there
is a coronavirus going around and I therefore no longer have any social obligations).</p>
<p><h2>Advent of Code vs other programming competitions</h2></p>
<p>Most of the Advent of Code problems are a lot easier than most programming competition problems, so if you have taken part in other programming competitions and found
the problems too hard, Advent of Code might be for you. The other edge of that sword is that implementation time is critical, and seconds count. On the easier problems
there simply isn't time to properly read the problem statement, you need to skim it as fast as you can and assume that the problem is whatever seems most likely based on
the few keywords you managed to pick out. I would definitely recommend practising on previous year's problems to get the hang of the
kinds of things that come up, the format of the questions, and so on.</p>
<p>Quite a lot of people record video of their solving and post it on YouTube. I recommend watching <a href="https://www.youtube.com/channel/UCuWLIm0l4sDpEe28t41WITA">Jonathan Paulson</a>, he finished
15th overall this year.</p>
<p>A lot of programming competitions are graded with <a href="https://www.spoj.com/">spoj</a> or <a href="https://www.domjudge.org/">DOMjudge</a>. In these competitions you submit your program,
and the system automatically runs your program against a collection of (secret) input sets, and decides whether your program passed or failed. This would not be suitable for Advent of Code because of
the sheer number of participants. For Advent of Code you are given an input set and have to produce the corresponding output. This drastically changes things, in a way that I like, because
it means you're no longer constrained to solving the problems with programming. You can solve them by hand, you can use a spreadsheet, you can use online tools, or any combination. You're
only graded by how quickly you can produce the final answer.</p>
<p>The idea of having part 2 hidden until after you've solved part 1 simulates the changing requirements encountered in real-world
programming tasks, unlike what you find in most programming competitions. It sometimes helps to write your part 1 solution with extensibility
in mind, because it might help on part 2. Although, my view is that you can not predict what the future requirements will be, and it's often easier
to extend the code later if it is written to be <i>simple</i>, rather than <i>extensible</i>.</p>
<p><h2>My solutions</h2></p>
<p>I wrote all of my programs in Perl, because it is the best language in the world. (Fight me.)</p>
<p>The Advent of Code problems are designed so that interpreted languages are not at a substantial disadvantage
relative to compiled languages, so there's no reason not to use whatever language you're most productive in. I think most of the top of the leaderboard uses Python.</p>
<p>If you want to read the code that I wrote for this year, it's in my <a href="https://github.com/jes/aoc2020">aoc2020 repo on github</a>, but note that unlike many Advent of Code
participants, I very rarely tidy up the programs after I've got the correct answer, so my programs tend to be pretty messy: I'm targeting implementation speed above almost all else.</p>
<p>I don't know how wise it is to publish code like this on github. I heard of a job applicant who had submitted a proper github repo
for a pre-interview code review. The reviewer didn't know the language that this program was written in, so he looked through the applicant's github profile for a project he could understand,
found the Advent of Code repo, and rejected the
applicant based on how disgusting the code was. Doesn't really seem fair, but if the reviewer didn't understand the purpose of Advent of Code, I can see why he made the mistake. But
I probably won't be applying for jobs any time soon so I'm not going to worry about it.</p>
<p><h2>Thoughts on some of this year's problems</h2></p>
<p>Stop reading now if you don't want spoilers.</p>
<p><h4>Day 1: Report Repair <a href="https://adventofcode.com/2020/day/1">[link]</a></h4></p>
<p>This problem asks you to find 2 entries that sum to 2020 from a list of input numbers, and report their product. A surprising number of people
wrote a solution like:</p>
<p><pre><code>for a in list:
    for b in list:
        if a+b == 2020:
            return a*b</code></pre></p>
<p>For the size of list given in the problem, this is plenty sufficient (and it is only day 1, after all: it's supposed to be easy), but this solution is unnecessarily <i>O(n<sup>2</sup>)</i>.
I prefer something more like:</p>
<p><pre><code>havenum[a] = 1 for a in list
for b in list:
    if havenum[2020-b]:
        return (2020-b)*b</code></pre></p>
<p>Assuming <tt>havenum</tt> is implemented as a hash table (or even an array would do in this case) then this solution is <i>O(n)</i>, which means it is suitable for much longer lists of numbers.</p>
<p>Also note that both pseudocode solutions shown above have the bug that they can report <tt><i>1010 * 1010</i></tt> if 1010 appears in the input, even if only once! This is a bug that a lot of
people - including me - implemented, but it didn't turn out to matter as 1010 was not present in the input. But these solutions are not technically correct.</p>
<p><h4>Day 5: Binary Boarding <a href="https://adventofcode.com/2020/day/5">[link]</a></h4></p>
<p>This problem asks you to take in a series of 10-letter directions to aeroplane seats and report the highest seat number encountered. The space inside the plane is split
up with <a href="https://en.wikipedia.org/wiki/Binary_space_partitioning">binary
space partitioning</a>, so the first letter of the directions tell you if you're in the front or back half of the plane, the second letter tells you if you're in the front or back half of
that half, and so on. It's kind of related to a binary search: instead of finding the position of an element by splitting the space in half at each iteration, you're just directly told the
half-space that you need to step into at each iteration. I've already spent plenty of time considering space partitioning schemes like this, and many years ago I published the only
documentation I'm aware of for the <a href="https://sauerbraten.org/">Sauerbraten</a> map format, which is based on <a href="https://en.wikipedia.org/wiki/Octree">octrees</a>:
<a href="https://incoherency.co.uk/interest/sauer_map.html">Sauerbraten map format documentation</a>.</p>
<p>The directions in the problem look something like "<tt>BFFFBBFRRR</tt>": the first 7 letters tell you which row to go to, and the last 3 letters tell you which seat to use in that row. The problem text explains
the mapping of directions to seat numbers (rows 0 to 127, columns 0 to 7 within a row, seat numbers are <tt>row*8+col</tt>). The "obvious" approach is to implement this like the binary search: take the letter at each position to divide the
search space, and report the seat number that is reached at the end.</p>
<p>The trick is that the mapping of directions to seat numbers means you can just directly map F to 0, B to 1, L to 0, and R to 1, and then interpret the result as a binary number
(so "<tt>BFFFBBFRRR</tt>" becomes <tt>1000110111 == 567</tt>). I recognised this immediately, but slowed myself down by blundering the mapping (I first had F and B reversed, then realised that mistake and
reversed all of the digits, then finally got it right), eventually submitting the correct answer after 5m14s.
If I had been smart enough to type the mapping correctly on the first try then I might have scored some points here.</p>
<p><h4>Day 8: Handheld Halting <a href="https://adventofcode.com/2020/day/8">[link]</a></h4></p>
<p>Implementing virtual machines has been a common theme from previous years of Advent of Code, and this problem looked like it was introducing the start of a new VM for this year, although
as it happened this was the only VM-related problem, to the disappointment of many.</p>
<p>This problem specified a very simple (and non-<a href="https://en.wikipedia.org/wiki/Turing_completeness">Turing complete</a>) instruction set which supports only
3 instructions: <tt>acc</tt> adds its argument to the accumulator, <tt>jmp</tt> is a relative jump, and <tt>nop</tt> does nothing. The problem input
is a program using these instructions. Part 1 asks you to find the value in the accumulator the first time any instruction is executed a second time. This was
pretty straightforward, just do what it says: execute the program until any instruction is executed a second time and then report the value in the accumulator.</p>
<p>The problem input would be an infinite loop if left alone, because there is no branching and no way to use the accumulator as a <tt>jmp</tt> argument, so any
program that executes any instruction twice will always loop forever.</p>
<p>Part 2 asks you to change exactly 1 opcode: change a <tt>nop</tt> to a <tt>jmp</tt> or a <tt>jmp</tt> to a <tt>nop</tt>, such that the program eventually terminates by jumping
to a position immediately after its last instruction.</p>
<p>The way to solve part 2 is to try changing each <tt>jmp</tt> and <tt>nop</tt> in the program consecutively, until
you find the one that makes the program terminate correctly. This is hard because some of the modifications you make result in the program entering an
infinite loop. In the general case, to prove that a program is not an infinite loop (i.e. that it will eventually terminate) would require solving the
<a href="https://en.wikipedia.org/wiki/Halting_problem">halting problem</a>. But the part 1 solution kind of gives the game away by having you already implement
a solution to the halting problem for this particular instruction set, based on the observation that if any instruction is executed twice, the program will loop forever.
Part of me wishes the part 2 problem had been a part 1 problem, so that you'd have to figure out for yourself how to detect infinite loops.</p>
<p>Somehow I got 46th place on part 2, although I don't think I had any particular advantage in this one. I must have just got lucky in correctly implementing it faster than others did.</p>
<p><h4>Day 10: Adapter Array <a href="https://adventofcode.com/2020/day/10">[link]</a></h4></p>
<p>You're given a bunch of power adapters in a bag that you are taking on a plane. Each adapter has some rated output voltage, and needs
to be powered by some other voltage that is between 1 and 3 volts lower than the output voltage. I found this problem confusing, because in my world-view, the kind of power
adapter that you take on a plane takes in 240v AC and gives out some lower voltage DC. That is, the input to the power adapter is a different type of thing from the output, and
stringing them together didn't even occur to me as a thing that you could do. I suspect this problem would be easier for people with no prior understanding of power adapters.</p>
<p><h4>Day 13: Shuttle Search <a href="https://adventofcode.com/2020/day/13">[link]</a></h4></p>
<p>A lot of people found part 2 of this problem quite tricky, because it requires you to know about the <a href="https://en.wikipedia.org/wiki/Chinese_remainder_theorem">Chinese Remainder Theorem</a>.</p>
<p>(<b>Update:</b> VeeArr <a href="https://old.reddit.com/r/adventofcode/comments/kknbq4/my_advent_of_code_story/gh3egxd/">points out</a> that there is an alternative solution and that Eric actually
intended it to be solved without knowing the Chinese Remainder Theorem!)</p>
<p>I had heard of the Chinese Remainder Theorem before because <a href="https://github.com/hex539">Robin</a> made us all try to understand it when I was on the university programming team.
I didn't actually understand it though, and I thought it would never come up in my life again.</p>
<p>After spending a while trying to solve day 13 using parts of number theory that I <i>did</i> know, I eventually Googled the Chinese Remainder Theorem and realised that it is exactly what I needed.
Rather than implement it myself, I just wrote <a href="https://github.com/jes/aoc2020/blob/master/13b.pl">a program</a> to restate the problem in terms of the Chinese Remainder Theorem and
then I solved the restated version of the problem using <a href="https://www.mathcelebrity.com/chinese.php">an online calculator</a>.</p>
<p>So I still don't know how to implement the Chinese Remainder Theorem, although I suspect I might be more likely to recognise where to apply it.</p>
<p>"ch1rh0" on reddit <a href="https://old.reddit.com/r/adventofcode/comments/kc5bl5/weird_math_trick_goes_viral/">pointed out</a> that the <a href="https://trends.google.com/trends/explore?date=2020-12-01%202020-12-24&q=Chinese%20remainder%20theorem">Google Trends graph</a> for "Chinese remainder theorem" on that morning was quite funny:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3115"><img src="https://img.incoherency.co.uk/3115/thumb"></a></p>
<p><h4>Day 20: Jurassic Jigsaw <a href="https://adventofcode.com/2020/day/20">[link]</a></h4></p>
<p>You're given a bunch of tiles that form a jigsaw puzzle. The tiles need to be rotated and flipped and fitted together. Unlike
a real-life jigsaw puzzle, you can't immediately tell which tiles go on the edge, because all of the tiles are perfectly square. You fit tiles together by
matching the patterns along their edges.</p>
<p>Part 1 asks you to multiply together the ID numbers of the 4 tiles forming the corners of the puzzle. I started out by doing the obvious thing: solve the
puzzle, take the ID numbers of the corner tiles, and then multiply them together. Halfway through doing this I realised that you could identify which tiles
go at the corners and edges by counting how many of the edges of a tile can possibly be matched with the edge of another tile. The corner tiles are the
ones which only have 2 edges which match other tiles.</p>
<p>Part 2 was an absolute bear of a problem. For this part you have to actually solve the puzzle, and then scan the resulting image looking for patterns that
look like a "sea monster":</p>
<p><pre><code>                  # 
#    ##    ##    ###
 #  #  #  #  #  #   </code></pre></p>
<p>And then report the number of <tt>#</tt> in the overall image that do not form part of any sea monster. Also there is no global reference for which way the image
is oriented, so
you have to attempt this for all 4 rotations, and for each option for mirroring the image. I had some good luck with this, in that I had already written
most of the puzzle-solving code for my first attempt at part 1, and managed to write the sea monster-detecting code correctly on the first try, which bagged
me 29th place on part 2.</p>
<p><h4>Day 25: Combo Breaker <a href="https://adventofcode.com/2020/day/25">[link]</a></h4></p>
<p>This problem describes a cryptosystem based on a door and a keycard communicating their public keys and using them to establish a shared encryption key. The problem
description is relatively oblique, because it talks about a method of repeatedly multiplying by a number and taking the result modulo some constant, but someone
on the subreddit pointed out that it is exactly the same as <a href="https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange">Diffie-Hellman</a> key exchange,
which is quite fun.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/advent-of-code-2020.html</link>
   <guid>http://incoherency.co.uk/blog/stories/advent-of-code-2020.html</guid>
   <pubDate>Sat, 26 Dec 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>All the gears, no ideas: an escape room puzzle</title>
   <description><![CDATA[I designed a puzzle for an escape room. The company ended up not wanting to pay for it, but I thought the puzzle was interesting
enough to be worth making for myself anyway.]]></description>
   <content:encoded><![CDATA[<p>I designed a puzzle for an escape room. The company ended up not wanting to pay for it, but I thought the puzzle was interesting
enough to be worth making for myself anyway.</p>
<p>This is what the puzzle looks like:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3103"><img src="https://img.incoherency.co.uk/3103/thumb"></a></p>
<p>And here's a demonstration of how it is solved:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/U0qjZtGJ-eM" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p><a href="https://jnicholls.uk/">James</a> suggested calling it "All the gears, no ideas", which is too irresistible a pun not to use.</p>
<p><h2>Prospecting</h2></p>
<p>I like puzzles, I like making stuff, and I like escape rooms. For a little while I've had the idea that I would like to work on puzzles for an escape room.
But I really don't want to do this as a <i>job</i>, I'm more after a kind of "paid leisure activity". (If you happen to work for an escape room and you
want me to work on puzzles for you, please get in touch!).</p>
<p>In September I sent out a short letter to every escape room I could find in Bristol, with an enclosed <a href="https://incoherency.co.uk/blog/stories/trick-chess-piece.html">3d printed chess piece</a> explaining
that I wanted to work on puzzles for them. The next day there was a bomb scare at a nearby Royal Mail sorting centre, and I wondered if their X-ray machines had mistaken
the <a href="https://mattshub.com/blogs/blog/gyroid-infill">gyroid infill</a> pattern for some unusual plastic explosive and they had therefore
destroyed it, meaning all my efforts had been for nought.</p>
<p>(It actually turned out that the bomb scare was caused by <a href="https://www.bristolpost.co.uk/news/bristol-news/royal-mail-bomb-squad-incident-4517876">an interesting scam</a> whereby
expensive items were sold on eBay, but the shipped package instead contained some sort of chemical reaction which would slowly burn through the shipping label, so that halfway through processing
it, Royal Mail would lose the package and would reimburse the seller for the supposed value of the items).</p>
<p>Anyway, I eventually received an email from a person who we'll refer to as <b>Baz</b>. Baz works at one of the escape rooms I contacted, but he doesn't want me to say which one in case
customers find this post while Googling it and spoil the puzzle.</p>
<p><h2>Puzzle idea</h2></p>
<p>Baz and I exchanged a few emails about puzzles and escape rooms, and he invited me in for an "interview" of sorts. The day before, he set me effectively the escape room
equivalent of a "whiteboard coding" problem. Roughly, it was:</p>
<p><blockquote>The players will find gears of different sizes lying around the room. Design a wall-mounted puzzle where the players have to fit the gears in the correct order so that cranking a handle on the
left turns all the gears, which operates a mechanism on the right. Ensure that the players can't bypass the puzzle by operating the mechanism on the right without using the geartrain.</blockquote></p>
<p>I designed this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3072"><img src="https://img.incoherency.co.uk/3072/thumb"></a></p>
<p>The idea is that each removable gear will be on a shaft, on which it is free to turn but can't fall off. The shaft will sit in the slot cut in the front panel, allowing the player to insert and
remove the gears, but not allowing the player to turn the gears without using the cranking handle. I was very pleased with this design and could not see any flaws in it. The arm on the right hand side
would be inside a mechanism used to unlock a box or similar. It would not be accessible by the players.</p>
<p>I produced this overnight to show Baz:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3074"><img src="https://img.incoherency.co.uk/3074/thumb"></a></p>
<p>I had quite a bit of trouble cutting the acrylic on the CNC machine. It seemed like it wanted to melt and stick to the tool and lift up off the table more easily than it would cut, but I sprayed a lot of water
over it while it was cutting and it came out acceptably.</p>
<p>With the puzzle assembled, I immediately discovered the first flaw: when you try to crank the handle, the forces are trying to lift the clockwise-rotating gears out of the slot
rather than rotate them. This should have been obvious. I was pretty disheartened by this flaw, but there was no time to fix it, so I just presented it to Baz anyway.
<a href="https://www.instagram.com/ruaribush/">Ruari</a> suggested replacing the slots with circular holes, and then the players have to drop the gears down from the top and skewer them with a shaft through the holes. That would
definitely prevent the gears from riding up in the slots, but it adds a bit too much of a "dexterity puzzle" component for my taste.</p>
<p><a href="https://jagd.me/">Jamie</a> pointed out that it might be possible to cheat by putting multiple gears in the final slot and turning them from the top instead
of using the cranking handle, and indeed this works :(. So this is another thing to fix.</p>
<p>But it turned out that Baz wasn't expecting much more than a convincing-looking sketch of the design, so he seemed pretty impressed with the demo regardless.</p>
<p><h2>Problems</h2></p>
<p>Baz and I identified the following problems with the prototype:</p>
<p><ol>
<li>the clockwise-rotating gears get pushed up in the slot</li>
<li>the acrylic is too flimsy because the slots mean there are long thin sections that are unsupported on 3 sides</li>
<li>should have more than 3 gears to make it a bit harder</li>
<li>you only get about 1/4 of a turn on the input gear to cover the whole range of the output gear; would be better if the players have to do a decent number of cranks</li>
<li>the output mechanism should actually do something instead of being an arm connected to nothing</li>
<li>you can cheat by putting multiple gears in one slot</li>
</ol></p>
<p>Your first thought for stiffening up the acrylic might be to add a support at the top,
but this won't work because it prevents the gears from fitting. The gears mesh against each other, which means the rightmost coordinate of one gear is further right
than the leftmost coordinate of the next gear. This means there can never be any place to put a support that doesn't interfere with the insertion of the gears.</p>
<p>So then we thought we would angle the slots so that the gears on the left slide down towards the right and the gears on the right slide down towards the left, and then there
is scope to support the acrylic in the centre. We also thought we could add a CNC-cut wooden frame around the perimeter of the acrylic to stiffen it up.</p>
<p>I quoted &pound;100 to construct a second prototype of the puzzle solving these problems, but Baz's bosses thought that was too expensive in light of the fact that they were closed
indefinitely due to the coronavirus laws. So they did not want to pay me. However it turns out I underestimated how much more work the second prototype would be than the
first, and &pound;100 was <i>way</i> too cheap.</p>
<p>But at this point I was far too invested in the puzzle to stop working on it, so I made one for myself anyway.
And since I'm not going to have daily consecutive crowds of rowdy hen parties
trying to break the puzzle in my house, I relaxed the requirement to support the acrylic and instead just used the same slot design but with thicker material.</p>
<p><h2>Calculating gear sizes</h2></p>
<p>One thing I didn't like about the first attempt is that I just guessed the gear sizes and roughly lined everything up so that it looked like it fit together. It did work but you can do better.</p>
<p><a href="https://en.wikipedia.org/wiki/Involute_gear">Involute gears</a> use a tooth profile that maintains a constant <a href="https://en.wikipedia.org/wiki/Pressure_angle">pressure angle</a>
throughout their rotation, which means the gears have a fixed speed ratio (the gear ratio), with no speed changes throughout the meshing of each tooth pair, as shown in this animation:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3108"><img src="https://img.incoherency.co.uk/3108/thumb"></a><br>
<small>(Image from <a href="https://en.wikipedia.org/wiki/Involute_gear">Wikipedia</a>.)</small></p>
<p>The contact point of the 2 meshing teeth always lies on a line that is tangent to the base circles of the gears,
and the force applied is always in the direction of this line.</p>
<p><blockquote>The involute gear profile was a fundamental advance in machine design, since unlike with other gear systems, the tooth profile of an involute gear depends only on the number of teeth on the gear, pressure angle, and pitch. That is, a gear's profile does not depend on the gear it mates with. Thus, n and m tooth involute spur gears with a given pressure angle and pitch will mate correctly, independently of n and m. This dramatically reduces the number of shapes of gears that need to be manufactured and kept in inventory.<br><small>from <a href="https://en.wikipedia.org/wiki/Involute_gear">Wikipedia</a>.</small></blockquote></p>
<p>If you imagine 2 gears meshing together as 2 smooth wheels, then the wheel with the same effective diameter as the gear is the <i>pitch circle</i>, and the diameter of this wheel is the <i>pitch
circle diameter</i>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3107"><img src="https://img.incoherency.co.uk/3107/thumb"></a><br>
<small>(Image from <a href="https://blog.misumiusa.com/understanding-gear-tooth-profile-gear-module-formula/">MiSUMi Mech Lab</a>.)</small></p>
<p>Gears are sized by their "module". The module is defined as the ratio of the pitch circle diameter to the number of teeth. Although the module effectively
describes the size of the teeth (in the sense that 2 gears with the same module will have the same size teeth), it is not something you can find by measuring the teeth directly.</p>
<p>The pitch circle diameter of a gear is the module multiplied by the number of teeth. Once you've settled on a module (I used 5.25 mm), and a number of teeth
for each gear, you can calculate the exact pitch circle diameter for each gear, and therefore the required distance between 2 gear centres to make the gears mesh together perfectly.</p>
<p>To get the gear reduction from left to right, I made each piece actually have 2 gears on it, fixed together, with the small gear of each driving the large gear of the next, and
with the gears alternating between having the small gear at the front and the large gear at the front.
This presents a bit of a problem because you need to make sure that each piece's large gear doesn't crash into the small gear of the next. I discovered that
I needed a safety margin of 5 teeth before 2 gears wouldn't crash into each other. I.e. if gear A has 20 teeth and gear B has 30 teeth, then to put a smaller
gear in the position of gear B and have it not interfere with gear A, the smaller gear would need to have no more than 25 teeth. It's not obvious to me
whether the margin of 5 teeth is a general property of involute gears or if it is related to the module size. Seems like it would be a general property, because increasing the module
size increases the size of the gear linearly.</p>
<p>I wrote <a href="https://github.com/jes/gears-puzzle/blob/master/gear-size-search">a quick Perl script</a> to search for a set of teeth that would make the puzzle
possible to assemble, with sensible-sized gears, without any unwanted meshing or interference, and with at least 2 different ways to mesh a gear
with both the input and output gear of the puzzle, to increase the number of ways to incorrectly half-solve it. There were a decent handful of solutions, so I selected one that made the distance
between each pair of gears as close together
as possible, to maximise the number of ways they could plausibly be inserted. If you read through the program, you might think it is unsound that I'm adding tooth counts
together and comparing them as if they are diameters. This actually works perfectly fine, because the diameter of a gear is just the number of teeth multiplied by the
module. Since all the gears use the same module, we can just assume a module of 1, and the maths all works out the same.</p>
<p>The tooth counts I ended up with were:</p>
<p><table border>
<tr><th>Gear</th><th>Big gear</th><th>Small gear</th></tr>
<tr><td>A</td><td>25</td><td>20</td></tr>
<tr><td>B</td><td>21</td><td>11</td></tr>
<tr><td>C</td><td>31</td><td>16</td></tr>
<tr><td>D</td><td>25</td><td>5</td></tr>
</table></p>
<p><h2>CAD</h2></p>
<p>With the tooth counts decided, it's time to CAD the parts. I started with a "master sketch" to define the locations and sizes of the gears and backplate.
The circles here represent the pitch circles of the gears (with a little bit extra diameter to make sure there is enough clearance for them to turn without binding).</p>
<p><a class="img" href="https://img.incoherency.co.uk/3106"><img src="https://img.incoherency.co.uk/3106/thumb"></a></p>
<p>The master sketch isn't directly used to make any of the parts, it just makes it a lot easier to reference the same locations and dimensions when designing the other parts.</p>
<p>You can see in the master sketch that each small gear drives the next big gear, except for the final gear. The small gear on the final removable gear does not mesh with anything, it is
just there so as not to make the final gear too obvious. The small gear on the output gear is sized so that it is able to mesh with one of the other gears, so that it is possible to make
a wrong choice and still get it to mesh correctly (although this would preclude the solving of the rest of the puzzle).</p>
<p><a class="img" href="https://img.incoherency.co.uk/3096"><img src="https://img.incoherency.co.uk/3096/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3097"><img src="https://img.incoherency.co.uk/3097/thumb"></a></p>
<p>Two of the removable gears have the big gear on the "outside", and the other two have it on the "inside". It is not possible to put a gear in the wrong way because the handle does not
fit in the slot on the inside. <a href="https://www.stavros.io/">Stavros</a> pointed out that I should have made the shafts symmetrical so as not to give any information about
which way around each gear must go. I don't actually know why this didn't occur to me, but it would definitely be an improvement.</p>
<p>To prevent the players from putting more than one gear in a single slot, I added the "slot blockers" which can move left and right with the sliding bar. With the bar in the left position, the
players are free to move gears up and down in the slots, but the output gear will not move because it is locked by a plastic piece at the end of the bar. With the bar in the right position,
the output gear is free to turn, but the gears can not ride up in the slots, and the players can not put extra gears in the slots, because they are blocked off.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3110"><img src="https://img.incoherency.co.uk/3110/thumb"></a></p>
<p>I discovered that the slot blockers would not quite be enough to prevent the players from cheating by reaching down with a larger gear, so I added "top blockers" as well. These are plastic
pieces connected to the top of the slot blockers that block off the top of the slot and completely preclude reaching down with a larger gear.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3109"><img src="https://img.incoherency.co.uk/3109/thumb"></a></p>
<p>Finally, rather than have the puzzle operate some unspecified locking mechanism for a box, I made it raise a little "shelf" up to an access hatch. The shelf can contain a small key,
a clue, or some other object that progresses the room.</p>
<p>The CAD files (including STL files for 3d printed parts, and CAM setups for CNC parts) are available <a href="https://github.com/jes/gears-puzzle">on github</a>.</p>
<p><h2>Construction</h2></p>
<p>The 3d printed parts are all in Prusament Galaxy Black PETG. I really like how this material looks, but it seems much more
brittle than other PETG filaments I have used. Not sure what's going on there.
Most of the CNC parts are made out of 19mm plywood. The plywood is not very good quality, I should really try and source some
"baltic birch" plywood for stuff like this in the future. The sliding bar is made of oak. I cut the outer dimensions of this on the table
saw, but I left a lot of burn marks and made a real mess of it. I've been using the tablesaw to cut brass and aluminium, so probably the blade
is getting blunt.</p>
<p>The clear plastic front panel is 5mm polycarbonate. I used polycarbonate because it is less brittle than acrylic, and also because
I found a good deal on <a href="https://www.ebay.co.uk/itm/392941037308">large sheets of it on eBay</a>. This time I searched online
to find suitable speeds and feed rates for cutting polycarbonate, instead of guessing, and it cut a lot more easily than the acrylic did.
Mainly this involved much lower spindle speed and faster feed rate.</p>
<p>I used a chamfering tool on the CNC machine to mark the centres of the holes that I needed to drill, but drilled them by hand because I have
so far had poor results trying to drill small holes with the CNC machine, that's something I need to work on.</p>
<p>I made a bit of a blunder in drilling the holes by hand, in that I accidentally drilled them all as clearance holes, instead of using a smaller
drill for the ones that I want screw threads to bite in. D'oh! <a href="https://falkus.co/">Martin</a> suggested drilling them out even larger,
gluing in dowels, chiseling them flush, and then re-drilling the correct size. This worked well, great success, crisis averted:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3101"><img src="https://img.incoherency.co.uk/3101/thumb"></a></p>
<p>Towards the very end of putting it all together, I realised that I had made a fatal design flaw! The small plastic "top blockers" actually block the insertion
of the gears even when the sliding bar is in the leftmost position:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3111"><img src="https://img.incoherency.co.uk/3111/thumb"></a></p>
<p>What a stupid mistake! This should have been obvious much sooner. The top blockers can't work for exactly the same reason that the clear panel can't be supported: the
entire width of the top needs to be open else the gears can't be inserted.</p>
<p>So for now I have just removed the top blockers. The rest of the puzzle works, but it can be easily defeated if you install the final gear correctly, and then
operate it by reaching down from the top with the largest gear.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3103"><img src="https://img.incoherency.co.uk/3103/thumb"></a></p>
<p><h2>Further work</h2></p>
<p>I think the puzzle as it stands is <i>OK</i>, but not great. The vulnerability that lets you solve it by poking the large gear down from the top is what
breaks it, really.</p>
<p>I think you could turn it into an acceptable escape room puzzle by increasing the height of the clear panel so that it is not possible to operate any of the gears
with another gear at the top, but I think there is probably scope for a more elegant solution if you go back to the beginning and rethink the whole thing.
The business about using the sliding bar
to block off the slots and stop the output from turning seems inelegant. I would be interested to see designs (or implementations!) for superior
versions of this puzzle.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/gears-puzzle.html</link>
   <guid>http://incoherency.co.uk/blog/stories/gears-puzzle.html</guid>
   <pubDate>Fri, 18 Dec 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made some aluminium keycaps</title>
   <description><![CDATA[I've made some aluminium keycaps on the CNC machine. I couldn't work out how
to do the CAM in FreeCAD (although I think I have now roughly figured it out), so I instead
wrote a program to render depth maps of STL files so that I could generate toolpaths
with my pngcam program (github).]]></description>
   <content:encoded><![CDATA[<p>I've made some aluminium keycaps on the CNC machine. I couldn't work out how
to do the CAM in FreeCAD (although I think I have now roughly figured it out), so I instead
wrote a program to render depth maps of STL files so that I could generate toolpaths
with my <a href="https://incoherency.co.uk/blog/stories/cnc-heightmap-toolpaths.html">pngcam</a> program (<a href="https://github.com/jes/pngcam">github</a>).</p>
<p>Here's what a finished keycap looks like, installed on the keyboard:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3083"><img src="https://img.incoherency.co.uk/3083/thumb"></a></p>
<p>I actually made 4 of these, because <a href="https://dartoxia.com/">Ben</a> told me people might buy
them if I listed them on Etsy, although I have only taken the time to sand and polish 1 and now can't be
bothered listing on Etsy. But if you happen to want to buy one for &pound;20 (plus postage if you live far away),
then send me an email and I'll polish one up and post it to you.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3040"><img src="https://img.incoherency.co.uk/3040/thumb"></a></p>
<p><h2>CAD</h2></p>
<p>I reused the CAD model I did for the <a href="https://incoherency.co.uk/blog/cad-dojo/stories/keycap.html">keycap CAD Dojo project</a> (which I've got a lot
more mileage out of than I expected!), but modified to have some retention tags around the perimeter:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3081"><img src="https://img.incoherency.co.uk/3081/thumb"></a></p>
<p><h2>Rendering a depth map</h2></p>
<p>With the CAD model exported to STL, I wrote <a href="https://github.com/jes/pngcam/blob/master/lib/Pngcam/Render.pm">a Perl module</a>
to software-render STL files into a depth map. Rasterising triangles is easier than I thought it would be. For each triangle
in the object, you just need to:</p>
<p><ol>
<li>draw the 3 lines that define the edges of the triangle, remembering the minimum and maximum <i>x</i> coordinate for each <i>y</i> coordinate</li>
<li>draw a horizontal line for each <i>y</i> coordinate, from minimum to maximum <i>x</i> coordinate</li>
</ol></p>
<p>And then you've drawn all of the triangles in a single colour. To draw a depth map instead of a single colour, you need to colour each pixel based on the <i>z</i> coordinate in the STL file. You can
calculate the <i>z</i> coordinate of each pixel on the edge of the triangle by linear-interpolating between the 2 vertices that define the ends of the edge, and you
can calculate the <i>z</i> coordinate of each pixel on the horizontal lines by linear-interpolating between the 2 points that define the left and right hand
edge of the horizontal line.</p>
<p>Since there can be more than one triangle that covers a given <i>(x,y)</i> coordinate, and we're trying to draw the view from above, we need to make sure that we only draw
the depth of the topmost triangle into each pixel. Your first thought might be to sort all of the triangles by <i>z</i> position, but this actually doesn't work because this is not
a well-defined ordering, because triangles have one <i>z</i> coordinate for each of the 3 vertices. The way this is typically done in computer graphics is to have a separate
depth buffer (basically a whole separate image that draws a depth map instead of the real colours), and write the <i>z</i> coordinate of each pixel into the depth buffer,
and only plot a pixel when the new <i>z</i> coordinate is higher than what is already in the depth buffer. Since we're only trying to draw a depth map, we can use the
main output image as the depth buffer itself.</p>
<p>So then the algorithm for plotting a given colour at a given pixel is just to check whether the new colour is brighter than what is already there, and only draw the new
colour if it is. And then we've succeeded in drawing a depth map of an STL file.</p>
<p>I added a flag to make it draw the depth map from the bottom instead of the top, so that we can machine the bottom side of the part separately, and after getting the output image I modified it in Gimp
to create 4 identical copies of the part, and to reduce pointless cut depth around the edge of the part
on the bottom side (since this will already have been cut out from the top side operation).</p>
<p><a class="img" href="https://img.incoherency.co.uk/3079"><img src="https://img.incoherency.co.uk/3079/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/3080"><img src="https://img.incoherency.co.uk/3080/thumb"></a></p>
<p>Hopefully you can understand what you're looking at here. Brighter pixels represent higher
<i>z</i> coordinates, so on the top depth map you have mostly-white in the middle (with a slight
curvy gradient), and then quite steep drops towards black at the edges.</p>
<p>These are then turned into G-code with <tt>pngcam</tt>.</p>
<p>(Those are the exact depth map images I used, so if you wanted to replicate this, you could
download those and make some yourself; it could also be used to make wooden
keycaps although I have not tried that yet).</p>
<p><h2>Machining</h2></p>
<p>Here's a video showing the machining process, but it's quite long and boring:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/c8TA_8joARo" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>All of the operations on the top side used a 4 mm ball-nose end mill. This is relatively easy. Clamp
the material down however you want, set the Z axis 0 position to roughly the top surface of
the material, and just run the G-code. Easy.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3078"><img src="https://img.incoherency.co.uk/3078/thumb"></a></p>
<p>The problem comes when you need to flip the part over to machine the bottom side. In total I had
12 attempts at making keycaps, and only for the final 4 (machined as a single batch) did I manage to
successfully align the bottom side with the top side. You can see some of the failed attempts
still attached to the base material, from where I was too demoralised to even bother separating them.</p>
<p>The solution I settled on is to clamp
down a straight edge parallel to the X axis and reference one side of the material to this
straight edge. That means when we flip the part over, we can easily return the material
square to the table, and we retain the Y coordinate for free. I also made
sure to drill a hole at a known position from the top side before unclamping the part, and then
pick up this hole on the bottom side after clamping it down, to act as a new reference for the
X coordinate.</p>
<p>This works but you need to make sure that the straight edge can't move when you unclamp the part,
and you need to make sure that you know exactly the relationship between the position of the
reference hole in your top-side and bottom-side coordinate systems.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3077"><img src="https://img.incoherency.co.uk/3077/thumb"></a></p>
<p>The bottom side was roughed out with the 4 mm ball end mill and then finished with a 2 mm ball end mill
because the 4 mm tool won't fit in all the gaps properly.</p>
<p>Finally, because I don't have a tool thin enough to cut the 1 mm cross shape to attach the keycap
to the switch stem, I bored out a 4 mm hole which will be useful later.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3076"><img src="https://img.incoherency.co.uk/3076/thumb"></a></p>
<p><h2>Finishing</h2></p>
<p>To make the keycap presentable, I first filed off the retention tags, then sanded down the tool marks
starting from about 160 grit sandpaper and ending at 2000 grit, and then polished it with
<a href="https://www.autosol.com/">Autosol</a>. I think I went up through the grits a bit too
fast as there are still some visible sanding scratches, but it's good enough to satisfy me.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3040"><img src="https://img.incoherency.co.uk/3040/thumb"></a></p>
<p>And this is how I'm going to fit the keycap on the stem.
A 3d-printed plastic insert that has the cross shape in it, and fits inside the 4 mm hole.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3085"><img src="https://img.incoherency.co.uk/3085/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/3084"><img src="https://img.incoherency.co.uk/3084/thumb"></a></p>
<p>(The keyboard definitely looked less dirty in real life than it does in the photo).</p>
<p><a class="img" href="https://img.incoherency.co.uk/3083"><img src="https://img.incoherency.co.uk/3083/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/aluminium-keycaps.html</link>
   <guid>http://incoherency.co.uk/blog/stories/aluminium-keycaps.html</guid>
   <pubDate>Sat, 28 Nov 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Sawing my dining table in half</title>
   <description><![CDATA[I liked my dining table, but it was a bit longer than necessary. It occurred to me that I could cut it in half, so
that's what I did.]]></description>
   <content:encoded><![CDATA[<p>I liked my dining table, but it was a bit longer than necessary. It occurred to me that I could cut it in half, so
that's what I did.</p>
<p>Here's the "before and after":</p>
<p><a class="img" href="https://img.incoherency.co.uk/3038"><img src="https://img.incoherency.co.uk/3038/thumb"></a> 
<a class="img" href="https://img.incoherency.co.uk/3039"><img src="https://img.incoherency.co.uk/3039/thumb"></a></p>
<p>The table is too large to get in/out of the house with the legs on, so the legs have to come off inside the house:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3066"><img src="https://img.incoherency.co.uk/3066/thumb"></a></p>
<p>I used the tablesaw, with blade retracted, as a workbench. I would have done this work outdoors because the tabletop is quite large,
but it was raining so I preferred to just manage inside the garage.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3045"><img src="https://img.incoherency.co.uk/3045/thumb"></a></p>
<p>I clamped down a guide for the circular saw and started making the cut. It was a bit of an awkward reach towards the
end, and I obviously wasn't paying attention properly, as my cut wandered away from the guide. D'oh!</p>
<p><a class="img" href="https://img.incoherency.co.uk/3046"><img src="https://img.incoherency.co.uk/3046/thumb"></a></p>
<p>I moved the guide over and had another go, and this time succeeded, although the tabletop will now not quite be a perfect
square. Never mind.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3047"><img src="https://img.incoherency.co.uk/3047/thumb"></a></p>
<p>I didn't cut all the way through the strips of wood at the edges with the circular saw, because I didn't want the tabletop to crash to the floor
at the end of the cut, and I didn't want to cut into the tablesaw. I finished the cut by hand.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3048"><img src="https://img.incoherency.co.uk/3048/thumb"></a></p>
<p>I initially understood this to be a solid-wood tabletop with an oak veneer on the top,
however I now discovered that it was an MDF tabletop with an oak veneer on the top and some other veneer on the bottom!
What a scam. If I'd known this when I started I would probably have chucked it away instead of trying to cut it in half.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3050"><img src="https://img.incoherency.co.uk/3050/thumb"></a></p>
<p>Now we need to work on the underside of the tabletop, so to avoid scratching the top surface I put a blanket over the tablesaw:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3049"><img src="https://img.incoherency.co.uk/3049/thumb"></a></p>
<p>My plan here was to take the edge piece off the end of the offcut and glue it on to the now-shortened tabletop. To
start with, we need mitred corners on the edge pieces that are already there. Spot the deliberate mistake:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3051"><img src="https://img.incoherency.co.uk/3051/thumb"></a></p>
<p>For some reason, my first thought was to cut the mitre backwards... I don't know why. Fortunately I realised my mistake before
I got too deep. I marked the mitres with a "speed square", which is a tool I bought years ago after reading something
that recommended it, but have found to be useful for almost nothing other than marking 45&deg; angles.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3052"><img src="https://img.incoherency.co.uk/3052/thumb"></a></p>
<p>After I cut my mitre, I found that the triangle of wood on the end was still attached with glue and a nail. I pried it off
with a screwdriver, but in so doing I also dislodged the edge piece that I wanted to keep, so I glued that back down and
clamped it, but I squeezed the clamp too hard and broke the handle off! This is not my day.</p>
<p>I plan to copy the broken part in FreeCAD as a <a href="https://incoherency.co.uk/blog/cad-dojo/">CAD Dojo</a> project and then make a replacement out of aluminium using the CNC machine.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3053"><img src="https://img.incoherency.co.uk/3053/thumb"></a></p>
<p>I've left a few apprentice marks, and ripped off a bit of the veneer, but I think this is going to work:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3054"><img src="https://img.incoherency.co.uk/3054/thumb"></a></p>
<p>Now I just need to liberate the edge piece from the offcut so that I can glue it on.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3055"><img src="https://img.incoherency.co.uk/3055/thumb"></a></p>
<p>I found that the MDF would split more readily than the edge piece would separate from the MDF.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3056"><img src="https://img.incoherency.co.uk/3056/thumb"></a></p>
<p>But using fine engineering techniques, and definitely not any brute force or ignorance, I eventually got it off:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3057"><img src="https://img.incoherency.co.uk/3057/thumb"></a></p>
<p>Quite a lot of MDF and veneer came off with it, so I then cleaned the glue surface up with a chisel:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3058"><img src="https://img.incoherency.co.uk/3058/thumb"></a></p>
<p>I glued both surfaces:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3059"><img src="https://img.incoherency.co.uk/3059/thumb"></a></p>
<p>And put it in place, with a couple of screws to hold the glue joint nice and tight:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3060"><img src="https://img.incoherency.co.uk/3060/thumb"></a></p>
<p>I found that the ends of this piece were bent away from the tabletop (probably due to the fine engineering techniques used in separating them earlier),
so I clamped them down to help the glue joint:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3067"><img src="https://img.incoherency.co.uk/3067/thumb"></a></p>
<p>Now we're getting somewhere. Just need to cut the side pieces down:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3062"><img src="https://img.incoherency.co.uk/3062/thumb"></a></p>
<p>The side pieces have a slight curve in the bottom of them, which I have simply ignored for now. If it bothers me that
they're wider at one end than the other, I can always take it apart again and run all of these pieces through the table saw to take the curve off.
But I don't think I care enough.</p>
<p><a class="img" href="https://img.incoherency.co.uk/3063"><img src="https://img.incoherency.co.uk/3063/thumb"></a></p>
<p>I planed a small chamfer on the cut edge to make it match the other edges a bit more:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3064"><img src="https://img.incoherency.co.uk/3064/thumb"></a></p>
<p>And finally took it inside and put the legs back on:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3065"><img src="https://img.incoherency.co.uk/3065/thumb"></a></p>
<p>That was quite a bit more of an ordeal than expected, and probably not worth it now that I know the whole thing is only
made out of MDF.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/dining-table.html</link>
   <guid>http://incoherency.co.uk/blog/stories/dining-table.html</guid>
   <pubDate>Thu, 19 Nov 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Seasonal.css: Give your website a seasonal colour scheme</title>
   <description><![CDATA[I've been working on a project that gives a CSS colour scheme that varies based on the day of the year, with a vague attempt
to match the colour to the season. In case you're wondering why my blog has a new purple colour scheme (at time of writing):
this is why. Have another look tomorrow if you want to see the same content in an imperceptibly-different purple.]]></description>
   <content:encoded><![CDATA[<p>I've been working on a project that gives a CSS colour scheme that varies based on the day of the year, with a vague attempt
to match the colour to the season. In case you're wondering why my blog has a new purple colour scheme (at time of writing):
this is why. Have another look tomorrow if you want to see the same content in an imperceptibly-different purple.</p>
<p>Check out the <a href="https://seasonal-css.incoherency.co.uk/">Seasonal.css project homepage</a>
or see the <a href="https://github.com/jes/seasonal-css">README on github</a>.</p>
<p>If you want, you can use it on your own pages:</p>
<p><pre><code>&lt;link rel="stylesheet" type="text/css" href="https://seasonal-css.incoherency.co.uk/seasonal.css"&gt;</code></pre></p>
<p><h2>What?</h2></p>
<p>Seasonal.css gives you a different colour scheme every day. Each day is only marginally different from the day before, but over the course
of the year, the entire range of the colour wheel is visited. Autumn has orange-purple colours, winter has purple-blue, spring has
blue-green, and summer has yellow-orange.</p>
<p>This animation shows the colour scheme on this blog throughout the year, at 30-day intervals:</p>
<p><a class="img" href="https://img.incoherency.co.uk/3027"><img src="https://img.incoherency.co.uk/3027/thumb"></a></p>
<p>This is accomplished by having Seasonal.css write the day's colours into <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties">CSS
variables</a> which can then be used to style the page.</p>
<p><h2>Why?</h2></p>
<p>From the README:</p>
<p><blockquote>One morning, while looking out of my window at the autumnal leaves on the trees, I thought to myself "my, what beautiful colours, I wish I could have these on my website". The idea fermented for a little while and I eventually realised that it would be possible for the colours of the website to change to match the colours of the seasons.
<br><br>
I enjoy how the colours of the natural world change throughout the year and wanted to bring the same experience to the web.</blockquote></p>
<p><h2>How?</h2></p>
<p>My initial idea was to manually define a colour scheme for each of the 4 seasons, and then interpolate between them with a few sine waves to generate
the colour scheme for each day. This did not work very well at all, because I had no understanding of colour theory. For example, the background
colour of one season had no relationship to the background colour of the next season (different saturation, brightness, etc.) because each colour
scheme was picked in isolation. This meant that interpolating between them resulted in nonsensical colour schemes.</p>
<p>A friend then linked me to Rob Weychert's <a href="https://v6.robweychert.com/blog/2019/12/dynamic-color-javascript-hsl/">dynamic, date-based colour</a>
project. (Rob also has a great post on <a href="https://v6.robweychert.com/blog/2018/02/v6-color/">colour theory</a> which is worth reading.)</p>
<p>Rob's approach was to split the HSL colour wheel up so that the first of each month takes a position on the colour wheel, and then linearly interpolate hues using
the colour wheel. Then define background, foreground, etc. saturation and lightness independently of the hue, so that they remain consistent throughout
the year. This works much better.</p>
<p>The biggest problem with Seasonal.css is that the colours from about mid-June to the end of July are a kind of muddy brown instead
of a bright summery yellow. The reason I have done this is that bright yellow doesn't give very good contrast against a light background, but the muddy
brown doesn't really convey "summer" very well. I'm interested in improvements to the colour scheme.</p>
<p>Seasonal.css is written in JavaScript, for the marginal benefit of being able to run the same code on the client as on the server.
I have used this on the project homepage to provide the live preview of the colour scheme for each day when you drag the slider.</p>
<p>To prevent the browser from caching yesterday's colour scheme, it sends headers:</p>
<p><pre><code>Expires: 0
Cache-Control: no-cache
</code></pre></p>
<p>That's not a proper date in the <tt>Expires</tt> header, but RFC2616 section 14.21 says:</p>
<p><blockquote>HTTP/1.1 clients and caches MUST treat other invalid date formats, especially including the value "0", as in the past (i.e., "already expired"). </blockquote></p>
<p><h2>Conclusion</h2></p>
<p>I'm pretty pleased with the end result, but I expect it would be a lot better if it were designed by someone with actual design
experience. If you think you can help please get in touch!
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/seasonal-css.html</link>
   <guid>http://incoherency.co.uk/blog/stories/seasonal-css.html</guid>
   <pubDate>Fri, 06 Nov 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>CNC toolpath generation from heightmaps</title>
   <description><![CDATA[I've been struggling with generating complex toolpaths in FreeCAD and thought that an easy approach would be to render a heightmap of the
part, and then generating a toolpath from that should be easy.
I understand that this is already a recognised technique, although I could not find an open source tool that
would do it for me. Most of the heightmap-related stuff I found on DuckDuckGo was to do with auto-levelling the bed.
And, anyway, it's a relatively simple idea and a fun challenge, so I did it myself.]]></description>
   <content:encoded><![CDATA[<p>I've been struggling with generating complex toolpaths in FreeCAD and thought that an easy approach would be to render a <a href="https://en.wikipedia.org/wiki/Heightmap">heightmap</a> of the
part, and then generating a toolpath from that should be easy.
I understand that this is already a recognised technique, although I could not find an open source tool that
would do it for me. Most of the heightmap-related stuff I found on DuckDuckGo was to do with auto-levelling the bed.
And, anyway, it's a relatively simple idea and a fun challenge, so I did it myself.</p>
<p>Get "pngcam" here: <a href="https://github.com/jes/pngcam">https://github.com/jes/pngcam</a>. I don't think there are any serious
"gotchas", it should mostly just work. But treat it with caution as it is under-tested and might make your machine crash into itself.
The documentation is not amazing, but I expect <tt>--usage</tt> will tell you most of what you want to know. You can visualise the generated
G-code by opening it in FreeCAD. Just initialise the Path workbench, then use "File -> Open" to open the G-code and you can explore it in 3D space in FreeCAD. It's worth
doing this to make sure it looks sensible before you run it on the machine.</p>
<p>Here's an example heightmap (232x650 px) and the part I made with it (60x168 mm):</p>
<p><a class="img" href="https://img.incoherency.co.uk/2991"><img src="https://img.incoherency.co.uk/2991/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2985"><img src="https://img.incoherency.co.uk/2985/thumb"></a></p>
<p>This post is comprised of two parts: <i>Implementation</i> and <i>Usage</i>. <i>Implementation</i> is about some interesting implementation details of pngcam, and <i>Usage</i> is about how I
used pngcam to make the wooden Klingon dagger.</p>
<p><h2>1. Implementation</h2></p>
<p><h3>1.1 Path generation</h3></p>
<p>The basic idea is that we'll make the tool travel in a zig-zag pattern to cover the entire rectangle described by the heightmap, and we'll move the Z axis up and down
at the same time so that we cut out the part.</p>
<p>The naive approach to this is to ignore the tool geometry and just take the Z height at a given X/Y coordinate directly from the brightness at the corresponding pixel of the image.
Here's an animation of what happens in 2 dimensions with this idea. The blue thing with black stripes is supposed to represent a ball-nose end mill. The black line is the desired part geometry. The red dot is
the point we've sampled from the heightmap image:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2987"><img src="https://img.incoherency.co.uk/2987/thumb"></a></p>
<p>You can see that on a perfectly flat horizontal surface, the geometry is reproduced correctly, but where the tool needs to
move up to clear space for a vertical feature, it doesn't move up until the <i>centre</i> of the tool touches that feature. This means features that raise up from a flat surface
end up too narrow, and features that sink into a flat surface end up too wide.</p>
<p>Maybe this is fine! Maybe we could stop here. For some parts this would be perfectly acceptable, and for parts where it's not acceptable you could just add a thickness to the part equal to the
radius of the tool, before rendering it to a heightmap, and then it would be cut out correctly.</p>
<p>But I wanted to do better, so I tried also sampling points at the very front and back of the tool (also the left and right side, in 3d, but not pictured):</p>
<p><a class="img" href="https://img.incoherency.co.uk/2988"><img src="https://img.incoherency.co.uk/2988/thumb"></a></p>
<p>I thought this would probably work acceptably, and it <i>almost</i> does, except for the tool-radius-sized chunk taken out of the top corners which I hadn't considered.
(It also over-cuts surfaces that are anywhere between perfectly-horizontal and perfectly-vertical, with the worst case being 45&deg;, but this isn't as bad as the chunk).</p>
<p>The solution is to sample every pixel in the heightmap under the footprint of the tool:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2989"><img src="https://img.incoherency.co.uk/2989/thumb"></a></p>
<p>And then we precisely follow the desired surface without cutting into the part. Effectively this is adding together the heightmap of the part and the heightmap of the tool,
and selecting the highest resulting height, which is the lowest point the tool can be moved to before it cuts into the part.</p>
<p>Unfortunately this is quite slow for high-resolution heightmaps because at every single step of movement we have to examine a tool-sized circle of
pixels. For small stepover values, these circles would mostly overlap the previous ones, so we'd be computing almost exactly the same thing again, just moved over slightly. These
<a href="https://en.wikipedia.org/wiki/Overlapping_subproblems">overlapping subproblems</a> suggest that a <a href="https://en.wikipedia.org/wiki/Dynamic_programming">dynamic
programming</a> solution might exist, but I can't quite find one. For now I just keep the heightmaps low-res.</p>
<p><h3>1.2 Path post-processing</h3></p>
<p>The initial path is a series of points defining stepover-sized line segments that show where the tool must travel to cut away the unwanted material and not cut into the work. There are then
post-processing steps to turn this path into usable G-code.</p>
<p><h4>1.2.1 Roughing</h4></p>
<p>You don't always want to cut the part to its full depth in a single pass, because this might either exceed the length of the flutes on the cutter, or might put an undue amount of stress
on the machine. This is particularly problematic when cutting metals, but also applicable in wood and plastics.</p>
<p>To limit the maximum cutting depth, I added a "stepdown" parameter. If you pass <tt>--step-down 2</tt> then pngcam will ensure that the tool is never cutting more than 2 mm into the material
by performing multiple roughing passes first, cutting in all locations that would otherwise exceed the configured stepdown limit.</p>
<p>If stepdown is limited to 2 mm, then we'll generate a series of movements to cut everywhere that wants to be deeper than 2 mm, with the tool at <tt>Z = -2 mm</tt>, followed by
another series of cuts everywhere that wants to be deeper than 4 mm, with the tool at <tt>Z = -4 mm</tt>, and so on until the full depth of the part is reached. These cuts are prepended to the
initial path so that when the main path is executed, the depth of material that we cut into never exceeds the configured stepdown value.</p>
<p><h4>1.2.2 Path segment consolidation</h4></p>
<p>At this point we still have a bunch of line segments that are mostly only as long as the stepover setting. This would produce extremely
long G-code files. In addition to the unwieldy G-code files, having lots of small steps prevents Grbl from being able to properly accelerate the tool. Grbl looks ahead 18 (I think?) G-code lines
when planning its motion, but if the segments are very short then 18 G-code lines is not going to be very far in the future, so Grbl needs to limit the tool speed so that it can account for the 19th
G-code line which might require it to rapidly reverse direction.</p>
<p>To solve these problems I made pngcam consolidate line segments by iterating over every point on the generated path, and removing points that lie on a direct straight line between the previous
and next point, as illustrated here:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2994"><img src="https://img.incoherency.co.uk/2994/thumb"></a></p>
<p>My initial approach for deciding whether 3 points were <a href="https://en.wikipedia.org/wiki/Collinearity">collinear</a> in 3-space was to calculate the gradient of the 2 implied line segments
in the X/Z plane and in the Y/Z plane and check whether the two X/Z gradients were equal and the two Y/Z gradients were equal (to within a reasonable tolerance). This mostly worked, except for the
case where (during the roughing pass, for example) the tool is moved vertically down and then vertically back up: in both of these cases the gradients are 0, so it looks like we can safely discard
the middle point, except obviously we can't because then the cut would not be performed. I solved this by checking the angle of the line segments with
<a href="https://perldoc.perl.org/functions/atan2">atan2</a> instead of the gradient, because this allows us to distinguish between up and down, and also checking the angle in X/Y in addition to
X/Z and Y/Z.</p>
<p><h3>1.3 Rapid moves</h3></p>
<p>Pngcam uses the G-code commands <tt>G0</tt> (rapid move) and <tt>G1</tt> (linear move). "Rapid moves" are generally for moving the tool around between cuts, rather than moving
the tool while cutting, and permit the motion controller to move in a non-straight line if it thinks that is faster.
During the roughing pass, pngcam sometimes has to pick the tool up and move it over to somewhere else without travelling through the work in between.</p>
<p>I was moving the tool around using <tt>G0</tt> to pick the tool up, then move it across, and then move it back down. Unfortunately, Grbl takes the view that it can do whatever it likes with rapid moves,
so if it sees some consecutive rapid moves, it seems to discard the first ones and go straight to the destination requested by the last one. This does indeed move the tool to that position
more rapidly, but it results in cutting a big gash out of the work piece! No bueno.</p>
<p>I solved this by using <tt>G1</tt> for the steps that pick the tool up and move it back down, and then it moved in the path I expected.</p>
<p><h2>2. Usage</h2></p>
<p><h3>2.1 Generating G-code</h3></p>
<p>With the program ready, we need a test part. A little while ago I watched &amp; enjoyed This Old Tony's <a href="https://www.youtube.com/watch?v=sjn6qeFzQCA">CNC Sword</a> video, so I
wanted to make a sword as well, but I thought
a small dagger would be a more sensible first attempt. I did a DuckDuckGo image search for various phrases like "dagger heightmap" and eventually found this "Klingon dagger" heightmap
in <a href="https://www.routerforums.com/cnc-routing/141425-old-models-new-depth-map-renders.html">a thread on RouterForums.com</a>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2995"><img src="https://img.incoherency.co.uk/2995/thumb"></a></p>
<p>I modified it a little bit in GIMP to reduce the wasted cutting around
the edges, keep the dagger attached with some retention tags, and reduce the thickness of the blade relative to the handle:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2990"><img src="https://img.incoherency.co.uk/2990/thumb"></a></p>
<p>I also produced an identical copy of the heightmap, but flipped horizontally, for cutting the back side of the dagger. (I've since added a <tt>--x-flip</tt> option to pngcam to make this easier).</p>
<p>I thought I'd first rough out the shape with a 4mm ball-nose end mill, and then cut the detail with a 2mm one. In case you're interested, I invoked pngcam as follows:</p>
<p><pre><code>pngcam --rapid-clearance 2 --step-over 2.4 --width 60 --tool-shape ball --tool-diameter 4 --depth 5 --xy-feed-rate 500 --z-feed-rate 200 --step-down 2 --clearance 0.1 --route both klingon-dagger.png > dagger-top-rough.gcode
pngcam --rapid-clearance 2 --step-over 0.6 --width 60 --tool-shape ball --tool-diameter 2 --depth 5 --xy-feed-rate 1000 --z-feed-rate 400 --route both klingon-dagger.png > dagger-top-finish.gcode
pngcam --rapid-clearance 2 --step-over 2.4 --width 60 --tool-shape ball --tool-diameter 4 --depth 5 --xy-feed-rate 500 --z-feed-rate 200 --step-down 2 --clearance 0.1 --route both klingon-dagger-bottom.png > dagger-bottom-rough.gcode
pngcam --rapid-clearance 2 --step-over 0.6 --width 60 --tool-shape ball --tool-diameter 2 --depth 5 --xy-feed-rate 1000 --z-feed-rate 400 --route both klingon-dagger-bottom.png > dagger-bottom-finish.gcode</code></pre></p>
<p>So the idea there is to run <tt>dagger-top-rough.gcode</tt> with the 4mm tool, then switch to the 2mm tool and run <tt>dagger-top-finish.gcode</tt>, then flip the work over, reinstall the 4mm
tool, and run <tt>dagger-bottom-rough.gcode</tt>, and finally switch back to the 2mm and run <tt>dagger-bottom-finish.gcode</tt>. <tt>dagger-top-rough.gcode</tt> looks like this, rendered in
FreeCAD:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2997"><img src="https://img.incoherency.co.uk/2997/thumb"></a></p>
<p>The red lines are <tt>G0</tt> rapid moves, and green lines are <tt>G1</tt> linear moves. Kind of hard to see but if you stare at it for a bit you might be able to understand what is going on.</p>
<p><h3>2.2 Running the machine</h3></p>
<p>If we only wanted to cut the dagger out of one side, we'd be ready to go, but since we need the cut on the back side to be aligned with the front side, we need a reliable alignment plan. My approach
to this was to manually mark out the rough rectangle in which I wanted the dagger, then drill a hole in the top left. I then clamped the wood onto the bed of the router, roughly square to the X and Y
axes, and zeroed the coordinates on the location of the hole I drilled. Relative to this hole, I then used the router to drill holes in the other 3 corners. Then when I flip the part over I can
pick up the alignment by checking whether the locations of the holes correspond to the correct coordinates, and adjusting the position until it does.</p>
<p>I started with conservative feed rate parameters to check that it was working, and then increased the feed rate override to 200% in
<a href="https://winder.github.io/ugs_website/guide/platform/">UGS Platform</a> to run at full speed.</p>
<p>I have a short video showing what the cutting looks like on the second side:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/QRKJ5Zmooc0" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>And the end result is this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2985"><img src="https://img.incoherency.co.uk/2985/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2986"><img src="https://img.incoherency.co.uk/2986/thumb"></a></p>
<p>I was originally going to cut off the tabs to release the dagger from the plank of wood, but I have no use for a tiny wooden dagger, and I like how it looks still attached to the board it was cut
from, so I think it is more interesting to leave it as is.</p>
<p>You can see there is one mistake: a vertical line cut too deep at the very top, about 1/3 of the way across. This was caused when the machine disconnected due to EMI and I failed to correctly
realign the Z axis. I hit the emergency stop before it cut into the actual part, so no harm was done. I thought I had solved the EMI problem but it still happens occasionally, I'd like to
get to the bottom of it. The USB cable I am using is shielded and has a ferrite choke on it, but maybe that's not enough? Or maybe the EMI is coming from inside the control box? Perhaps a grounded
metal box around the Arduino would help? I'd be interested in hearing from anyone who knows about this stuff. Firstly on how to work out exactly where the EMI is affecting things, and secondly
on what to do about it.</p>
<p><h2>3. Next</h2></p>
<p>With pngcam, I (and also you) have gained the ability to turn a heightmap into G-code. Sadly this is only one half of the puzzle: we also need a way to turn a CAD model into a heightmap.
You can do this by loading the model in Blender and configuring Blender to render a heightmap, but that's quite inconvenient. I've been reading up on triangle rasterisation algorithms,
and I've never implemented one before,
so I think I am quite likely to write a software renderer which will take in an STL file and produce a heightmap. With that in place, we'd almost be able to operate the CNC router with
the same level of ease as the 3D printer: just stick in an STL file and get out ready-made G-code. No manual toolpath planning required!</p>
<p>Obviously for certain part geometries, and particularly for engineering parts, it would
be quicker and more accurate to use toolpaths generated with more traditional CAM software. For decorative parts, and complex shapes, I think pngcam might be a useful workflow. I actually
started working on pngcam in the first place because I was challenged to machine an aluminium keyboard keycap but found myself unable to generate toolpaths for it in FreeCAD. The FreeCAD
Path workbench is basically designed for generating cuts that <i>either</i> move the tool in the X/Y plane or in the Z axis. It is hard (if not impossible) to generate toolpaths that follow
complicated surfaces. Hopefully this improves in future, but in the meantime I'm enjoying myself working on pngcam.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/cnc-heightmap-toolpaths.html</link>
   <guid>http://incoherency.co.uk/blog/stories/cnc-heightmap-toolpaths.html</guid>
   <pubDate>Sat, 24 Oct 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>First steps into CNC machining</title>
   <description><![CDATA[I have bought a "6040" CNC router, and have been getting to grips with how to use it.
This journey started with converting the machine to Grbl because I'm not interested in running
proprietary software. Once Grbl was all working correctly, I clamped a small piece of plywood to the bed, fitted a 2mm end mill and made my first cuts, manually
"jogging" the tool position using the buttons in the UGS interface.]]></description>
   <content:encoded><![CDATA[<p>I have bought a "6040" CNC router, and have been getting to grips with how to use it.
This journey started with <a href="https://incoherency.co.uk/blog/stories/6040-cnc-grbl-arduino.html">converting the machine to Grbl</a> because I'm not interested in running
proprietary software. Once Grbl was all working correctly, I clamped a small piece of plywood to the bed, fitted a 2mm end mill and made my first cuts, manually
"jogging" the tool position using the buttons in the <a href="https://winder.github.io/ugs_website/">UGS</a> interface.</p>
<p>I have <a href="https://www.youtube.com/watch?v=GxodKLoLdfY">this video clip</a> of
what happened, but it was basically uneventful and worked fine! This is what I ended up with:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2933"><img src="https://img.incoherency.co.uk/2933/thumb"></a></p>
<p>Great success!</p>
<p><h2>Generating toolpaths</h2></p>
<p>Now that I'm clearly an expert at operating the machine, it was time to fire up FreeCAD's <a href="https://wiki.freecadweb.org/Path_Workbench">Path workbench</a> and
generate some G-code. I modelled this part:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2934"><img src="https://img.incoherency.co.uk/2934/thumb"></a></p>
<p>Although at this stage I couldn't work out how to generate a toolpath for the square pocket around the edge, so I only ended up
cutting out the circular holes. This worked, but it was a very rough cut:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2935"><img src="https://img.incoherency.co.uk/2935/thumb"></a></p>
<p>I have <a href="https://www.youtube.com/watch?v=L2JW4TT5e5E">this video</a> of it. You can see that it took a pretty aggressive bite, which I think is
why there is so much tear-out around the edges of the holes. I learnt that for next time I'll need to go into the tool settings in FreeCAD
and turn down the feed rate.</p>
<p><h2>Making a part from CAD</h2></p>
<p>At this point I wanted to try cutting some aluminium, so I modelled a more realistic test part and generated toolpaths for it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2981"><img src="https://img.incoherency.co.uk/2981/thumb"></a></p>
<p>(This is the toolpath I eventually settled on, with very small step down, not the first one I tried).</p>
<p>You might have to zoom in to properly see the toolpaths, but you should be able to see that this time I generated a facing cut on the top surface,
a hole all the way through with a step at the bottom, and a slot that only goes to half the depth.</p>
<p>You can also see that with the outer profile I have left some "tags" of material in place (the path moves up and then down to leave a triangle shape behind). This is so that the part does not break loose towards the
end of the cut. These tags are then broken by hand to free the part from the stock it is cut out of. These are added by a toolpath <a href="https://wiki.freecadweb.org/Path_Dressup">"dressup"</a>
in FreeCAD. There
are quite a few dressup types available, they all work by taking in a path that has already been generated, and modifying it in some way (here, by making it
avoid the locations of the tags).</p>
<p>I was still afraid to try aluminium, so I started by cutting this part out of MDF. It went quite well and I got this out:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2949"><img src="https://img.incoherency.co.uk/2949/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2948"><img src="https://img.incoherency.co.uk/2948/thumb"></a></p>
<p>It seems a facing cut is not a sensible thing to do to MDF, but it cleaned up OK with a light sanding:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2951"><img src="https://img.incoherency.co.uk/2951/thumb"></a></p>
<p><h2>Aluminium</h2></p>
<p>There's no point procrastinating any further: it's time to clamp some aluminium down and see what happens. I have
<a href="https://www.youtube.com/watch?v=_wThR3A07q4">this video</a> of what happened. To cut a long story short, I got about this far before the end mill broke:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2982"><img src="https://img.incoherency.co.uk/2982/thumb"></a></p>
<p>This was actually quite encouraging, because it showed that the machine is perfectly capable of cutting aluminium, which is what I was most concerned
about. I think the end mill broke because I was still taking too large a cut, and also I was using one of the "free" end mills that came with the machine, so
I have no idea what kind of quality to expect from them, or if they are even suitable for aluminium in the first place.</p>
<p>FreeCAD seems to default to using a "step down" of 100% of the tool diameter. That seems like quite a big ask for a 2mm tool, so after observing this
failure I reduced the step down to only 20% of the tool diameter, or 0.4mm per pass.</p>
<p>Having regenerated the toolpaths with a reduced step down, I attempted to realign the tool with the (0,0,0) point on the work, and then try again.
The cutting worked great, although I did not get the alignment very close, so the features cut by the 2nd attempt do not line up very well with the features
cut by the first attempt.</p>
<p>I also found that about 30 minutes in, the machine stopped moving completely and UGS reported that it was disconnected from Grbl. This was a bit concerning.
I looked in <tt>dmesg</tt> and found that Linux suspected <a href="https://en.wikipedia.org/wiki/Electromagnetic_interference">EMI</a> was the cause of the
disconnection. I had this problem once before while setting up Grbl and found it went away when I moved the computer further away from the control box, so this time
I just moved the USB cable away from the control box and tried to reconnect and it worked fine. Now that I've got the control box in a more permanent location,
I have the USB cable on a relatively taut run directly away from the box, and I haven't experienced this problem again.</p>
<p>This time I didn't move or reset anything, so I thought I would not need to realign the tool to the work because UGS still thought it knew where the tool was.
Unfortunately this didn't quite work and I ended up a couple of mm away from where it should have been, thus introducing a 3rd set of features not aligned with
either of the previous two. Oh, well.</p>
<p>I deleted all the G-code that I was confident had already been executed, and sent the rest, and the part completed with no more failures! Great success, ish. After filing
off the tabs left around the edge, this is what I got:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2952"><img src="https://img.incoherency.co.uk/2952/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2953"><img src="https://img.incoherency.co.uk/2953/thumb"></a></p>
<p>I'm mostly pleased with this, although I would have been more pleased if all the features on the aluminium part lined up with each other.</p>
<p><h2>Puzzle design</h2></p>
<p>Now that I'm obviously an expert at both operating the machine <i>and</i> generating toolpaths for it, and have demonstrated my prowess in machining
parts from aluminium, it's time to make something "useful". I have 3d printed quite a lot of puzzles based around the idea of extracting a trapped coin, so
I thought I'd start with one of those. This particular puzzle is a clone of the "penny pincher" puzzle. I think I first saw the idea on a YouTube video from
a Maker Faire, but I can't find that one now. You can see an example of the idea in <a href="https://www.youtube.com/watch?v=O-Q6O-yDes0">this video</a>.</p>
<p>It has 3 levels that can all pivot around a bolt. The coin is trapped in a recess in the bottom level. To remove the coin you need to rotate the middle level away from
the bottom level, but it is prevented from rotating by a peg in the bottom level that engages a slot in the middle level. So you need to move the middle level
horizontally before it will rotate, but it is prevented from moving horizontally by an unseen ball bearing that hits against the pivot bolt. So
you need to tip the puzzle upside down to allow the ball bearing to move into a recess inside the top level, and then you can rotate the top level away, which will
then allow the middle level to slide horizontally, which will then allow the middle level to rotate, allowing the coin to be removed.</p>
<p>Ideally it would be impossible to slide the middle level until the top level is rotated, but since I'm relatively new to this I kept life simple for myself and made the middle and top levels
perfectly flat. Here's the CAD:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2954"><img src="https://img.incoherency.co.uk/2954/thumb"></a></p>
<p>Hopefully you can understand how it works if you follow along with the description above.</p>
<p>The thickest aluminium sheet I have is 6mm, which means the top level of the puzzle can't be any taller than 6mm, which means the ball bearing has to be smaller than this.
I didn't have one suitable, but I proceeded anyway and have ordered some 4.5mm ball bearings.</p>
<p>Each of the 3 parts can be completely machined from just 1 side, except for the pockets for the bolt head and nut. This is good because it means I can test everything with only
1 setup per part, and then come back and make the pockets in a second setup, after I know everything else has worked.</p>
<p>Having learnt from my difficulties in aligning the tool with the work before, this time I made sure to put the origin on the axis of the bolt hole, so that I can always pick up the centre
again by jogging the machine so that the tool lines up with the bolt hole on the part.</p>
<p><h2>Making puzzle parts</h2></p>
<p>I clamped down some aluminium, zeroed the Z axis on the surface of the metal, and just as I started jogging X and Y into position, the end mill broke. I hadn't even started cutting anything!
I think my "zero" of the Z axis was a bit more aggressive than necessary and the tool was actually pressed into the metal slightly when I was trying to move it in X and Y. D'oh!</p>
<p>I didn't have any more 2mm end mills, so I chucked up a 3mm end mill instead and went back to FreeCAD to regenerate all my toolpaths. This time I moved the Z axis away from the part before moving X and Y, which worked
a lot better.</p>
<p>I don't have a lot of photo or video from this, because I was busy concentrating on not messing it up, but it mostly went well, with no more broken end mills and no disconnection due to EMI.
The biggest mistake was that the toolpaths for the slot in the middle piece and the "peg" on the bottom piece left rounded corners instead of straight sides, because the generated toolpath
attempted to trace the outline of the flat top area, without knowledge that the sides of it are empty space and can be safely cut into:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2958"><img src="https://img.incoherency.co.uk/2958/thumb"></a></p>
<p>I fixed this by operating the tool manually, using the GUI, but I'm not entirely sure what would be the best way to generate toolpaths to do this, maybe do the "adaptive" process like this followed by a "profile" around the outside of the peg?</p>
<p><a class="img" href="https://img.incoherency.co.uk/2959"><img src="https://img.incoherency.co.uk/2959/thumb"></a></p>
<p>With all the machining done, it's time to break the parts out of their base material. Some of them didn't quite cut all the way through, leaving a thin foil of material:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2960"><img src="https://img.incoherency.co.uk/2960/thumb"></a></p>
<p>This was easily broken through, but I'd have preferred to make the tool cut slightly into the wasteboard rather than leave material on the part.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2961"><img src="https://img.incoherency.co.uk/2961/thumb"></a></p>
<p>I broke the solid tags with a hammer and chisel, and then we have to tidy up the edges:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2962"><img src="https://img.incoherency.co.uk/2962/thumb"></a></p>
<p>Most of the flashing is easily removed, and then it's just a case of filing the tags down, and a light sanding to disguise the apprentice marks:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2963"><img src="https://img.incoherency.co.uk/2963/thumb"></a></p>
<p>Repeat this for each part:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2964"><img src="https://img.incoherency.co.uk/2964/thumb"></a></p>
<p>And bolt the puzzle together:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2966"><img src="https://img.incoherency.co.uk/2966/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2968"><img src="https://img.incoherency.co.uk/2968/thumb"></a></p>
<p>Great success, everything fits. The edges are not very neat, I will try to use tags more sparingly in future.</p>
<p><h2>Enclosure</h2></p>
<p>At this point I built an enclosure for the machine, primarily to stop it spraying aluminium shavings all over my garage, but also to
keep the noise down a bit, and protect the machine from welding and grinding sparks in the future. I wanted to make the whole thing out of
perspex, but perspex is surprisingly expensive, especially in large sheets of a decent thickness. So instead I made it out of materials
I already had on hand.</p>
<p>It's not very well made, but it should do the job.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2969"><img src="https://img.incoherency.co.uk/2969/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2970"><img src="https://img.incoherency.co.uk/2970/thumb"></a></p>
<p>The idea is that when the door is closed I can still see what's going on inside through the window, and when the door is open I have unimpeded
access to the inside. I thought I had a spare handle lying around which I wanted to use, but I couldn't find it. <a href="https://jnicholls.uk/">James</a> generously
supplied me with a free kitchen cupboard door handle:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2980"><img src="https://img.incoherency.co.uk/2980/thumb"></a></p>
<p><h2>Puzzle parts, 2nd setup</h2></p>
<p>It's tempting to stop here, given that the puzzle works (or at least, it would do, if I had a ball bearing that would fit inside). But the point here is to learn
a bit about how to make parts with this machine, so let's proceed.</p>
<p>To mount the bottom puzzle piece upside down on the wasteboard, I first cut a small pocket out of it "manually" so that the raised peg can sit down into the board. I could have
had the peg overhanging the edge of the board, but I couldn't be bothered rejigging the hold-down clamps, and this way seemed more interesting:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2973"><img src="https://img.incoherency.co.uk/2973/thumb"></a></p>
<p>I then manually aligned the tool with the centre of the bolt hole:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2975"><img src="https://img.incoherency.co.uk/2975/thumb"></a></p>
<p>And ran the G-code to get a hexagonal pocket for the nut. I did take <a href="https://www.youtube.com/watch?v=hTcgnMGLeQQ">a video</a> of this step, which also shows a bit of operating
UGS and showing how the enclosure opens and closes. The result is this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2976"><img src="https://img.incoherency.co.uk/2976/thumb"></a></p>
<p>I wasn't sure if I'd need to come in again with a <a href="https://wiki.freecadweb.org/Path_DressupDogbone">dogbone dressup</a> to make the nut fit in the hole,
but this wasn't necessary and it was easy to press-fit the nut using the vice:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2977"><img src="https://img.incoherency.co.uk/2977/thumb"></a></p>
<p>A similar setup is used to make the circular hole for the head of the bolt, and the whole thing can be put together:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2978"><img src="https://img.incoherency.co.uk/2978/thumb"></a></p>
<p><h2>UGS</h2></p>
<p>So far I have only been using UGS "Classic". This is because I was initially unable to get UGS "Platform" to work on my laptop. It segfaulted on startup,
even when using the version that bundled a presumed-working version of Java. I have since replaced Ubuntu 18.04 with 20.04, and now UGS Platform works fine.
I've connected it up and jogged the machine around to test it but have not yet ran any G-code with it. UGS Platform appears to be a substantially superior
program, it gives you much more control over the machine and also includes a visualisation of the toolpaths.</p>
<p>I think it would be handy to have a plugin in UGS that would quickly generate and run paths for simple operations like circular holes, square holes,
slots, etc. so that I can more easily make quick changes to a part without having to go all the way back to FreeCAD.
That said, I looked at the UGS <a href="https://winder.github.io/ugs_website/dev/plugin/">development documentation</a>, and it seems very Java, so perhaps I won't do it.
It might be almost as handy to just have an external program write a G-code file which can then be loaded in UGS, and probably something like this already exists.</p>
<p><h2>Comparison to 3d printing</h2></p>
<p>The CNC router is not nearly as convenient as the 3d printer. Compared to the 3d printer, the router requires:</p>
<p><ul>
<li>hand-holding in toolpath generation</li>
<li>base material of sufficient dimensions to contain the part</li>
<li>end mills of appropriate shape, size, and material</li>
<li>clean up of chips at the end</li>
<li>manual finishing to separate the part from the stock</li>
</ul></p>
<p>Whereas the 3d printer can print all part geometries out of the same spool of base material, can make all feature shapes using the same nozzle, doesn't create any waste material (modulo support structure),
and toolpaths are automatically generated by the slicer.</p>
<p>However, the CNC machine has the big advantage that it can make parts out of a wider range of materials, it can make much bigger parts, and it gives finer control over the surface finish.</p>
<p>I think for small parts where plastic is acceptable, 3d printing is definitely the way to go just because it's so easy.</p>
<p><h2>Remarks on the 6040 CNC machine</h2></p>
<p>I am pleasantly surprised by the machine. It came almost completely assembled, which made putting it together a doddle, and it is much sturdier than I expected, but there are a
few things that I think could easily be improved:</p>
<p>The hold-down clamps are very poor. The bolt that slides in the T-tracks on the bed is just a normal hex-head bolt and is not large enough to prevent the head from rotating. I have
developed a technique of holding the loose end of the bolt with a pair of pliers while I tighten or loosen the wing nut, but they should have just supplied proper T-nut bolts. I'll probably
replace them.</p>
<p>The text on the front panel for spindle speed control has "PC" and "Manually" modes, surely this should say "Manual" instead of "Manually". Similarly, the labelling on the back panel
for the spindle power says "SPANDLE". Given how popular the machine is, it seems totally implausible that nobody involved with it speaks English well enough to spot these mistakes, so I wonder why
they still haven't been corrected?</p>
<p>The stepper motors have knobs on them that would appear to allow for easy manual operation, but the stepper motor drivers are wired from factory so that the steppers are always switched on (and therefore
holding position) whenever
the machine is powered on, which means the only time you have a chance of manually turning them is when the machine is switched off so you can't cut anything. Surely either make it
so the steppers are easily switched off, or don't bother adding a manual knob to the back of each one?</p>
<p>That's nitpicking though, really. It's a great machine, much more capable than I require.</p>
<p><h2>Lessons learnt</h2></p>
<p>I found that I got a decent cut in aluminium with a 3mm 2-flute carbide end mill with a feed rate of 200 mm/min, step down of 0.4mm and step over of 0.4mm. From first
principles, I think I would extend tool life by increasing the step down and decreasing the step over, on the basis that I am currently only ever using the bottom 0.4mm of the tool
height. Perhaps I should experiment with this. I also wonder if there is a reasonable DIY method to grind off the bottom 0.4mm of a worn-out tool so that I can get a sharp edge again, comparable to
sharpening a drill bit? Might be worth looking into.</p>
<p>I need to manually start the spindle before sending G-code, because it takes a long time for the VFD to spin the spindle up to top speed. Maybe I could reconfigure the VFD
to spin up faster, but the documentation is sorely lacking. If you just send G-code without manually waiting for the spindle to speed up, then it might plunge into the work before reaching
the required speed.</p>
<p>I sprayed water and WD-40 on the first cuts I did in aluminium under the belief that it would need some cooling, but I found that this only serves to gum up the chips and keep them
from getting away from the tool. I did the later parts with no part cooling and the part didn't heat up noticeably, and the chips cleared the cut more easily, so I probably
won't be using coolant on aluminium.</p>
<p>I should tell FreeCAD to cut a bit deeper than the required thickness of the part so that I don't have to manually peel away a thin foil of aluminium left on the bottom.</p>
<p>I should use tag dressups sparingly because they are hard to remove neatly, and leave a poor surface.</p>
<p>The USB cable should be kept as far away from the control box as possible, to reduce electromagnetic interference.</p>
<p>It is helpful to have a plan for how to realign the tool with the work. Even if the part can be made in a single setup, something might go wrong and it might require realigning, so it's
helpful to be able to do it accurately.</p>
<p>If the Z axis is zeroed before X and Y, I should move the Z axis back up before trying to move X and Y, lest I scratch the top surface in the best case or break the end mill in the worst case.</p>
<p><h2>Still to learn</h2></p>
<p>I don't know how to calculate what speed I should run the spindle at. So far I have been running it at full speed of 24,000 rpm because I read that it produces the most power at the highest speed. I
also read that for cutting metal you generally want lower rpm, so I don't know which of those 2 properties takes precedence. It is not obvious to me that spinning the tool more slowly is going to help
anything, seems like it could only hurt.</p>
<p>I don't know how to get FreeCAD to rotate the job to let me work on the "bottom" face of the part. So far my only solution is to manually rotate the part itself and then use the Path workbench to generate toolpaths
on the new top face. Seems like this is pretty basic though, so the Path workbench probably supports it, I just need to find out how.</p>
<p>I don't know how to get the generated toolpath to run into empty space at the side of a feature where I want square edges instead of rounded edges. Again this seems pretty basic so is probably
possible, just something I need to learn. I think in the worst case I could manually edit the generated G-code to extend the path in the relevant places, although this seems error-prone.</p>
<p>That's all I have to say about my adventures in CNC machining so far. If you can help, or have any comments, please get in touch.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/first-steps-into-cnc-machining.html</link>
   <guid>http://incoherency.co.uk/blog/stories/first-steps-into-cnc-machining.html</guid>
   <pubDate>Mon, 05 Oct 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to convert a 6040 CNC machine to Grbl</title>
   <description><![CDATA[The 6040 CNC machine comes in 2 flavours: parallel port and USB. I don't have a parallel port on the laptop I was
intending to operate it with, so I chose the USB option. This is possibly a "mistake" as the USB option uses
a proprietary USB interface board which is only compatible with Mach3
and therefore only compatible with Windows. But now that I've got it set up with Grbl, I think I prefer this system to
what I would have with a parallel port controlled by LinuxCNC.]]></description>
   <content:encoded><![CDATA[<p>The 6040 CNC machine comes in 2 flavours: parallel port and USB. I don't have a parallel port on the laptop I was
intending to operate it with, so I chose the USB option. This is possibly a "mistake" as the USB option uses
a proprietary USB interface board which is only compatible with <a href="https://www.machsupport.com/software/mach3/">Mach3</a>
and therefore only compatible with Windows. But now that I've got it set up with Grbl, I think I prefer this system to
what I would have with a parallel port controlled by LinuxCNC.</p>
<p>I understand that Mach3 normally works by writing step/direction signals to the parallel port. The USB interface board that comes with the 6040 CNC
machines has a driver that Mach3 uses to speak USB instead. <a href="https://www.linuxcnc.org/">LinuxCNC</a> also normally works by writing step/direction signals to the parallel
port but there is no Linux driver for this proprietary USB thing.</p>
<p>The LinuxCNC forums <a href="https://forum.linuxcnc.org/38-general-linuxcnc-questions/34248-chinese-cnc-3020-6040-usb-variant">are full of</a> people trying
to operate USB machines with LinuxCNC and being told that USB is not a sensible way to operate a CNC machine because USB is not sufficiently real-time.
I disagree. I think <i>LinuxCNC and parallel ports</i> is not a sensible way to operate the machine because <i>Linux</i> is not sufficiently real-time, USB or not. In
my opinion, motion control
should be offloaded to a microcontroller, and then the PC doesn't need to pretend to be a real-time system, which is exactly the way <a href="https://github.com/gnea/grbl">Grbl</a> does it.
Grbl is a motion control system that runs on an ATmega328p (e.g. an Arduino). It takes G-code over USB serial and writes step/direction signals to the GPIO pins.</p>
<p>So let's assume you've got your 6040 CNC machine, and you're onboard with the idea that Grbl is the best way to control it. What do you need to do?</p>
<p>You have 3 main tasks:</p>
<p><ol>
<li>install Grbl on an Arduino</li>
<li>get Grbl controlling the stepper motors</li>
<li>get Grbl controlling the spindle speed</li>
</ol></p>
<p><h2>Safety notices</h2></p>
<p>Don't do anything dangerous. If you do do anything dangerous, don't get hurt. If you do get hurt, don't blame me.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2944"><img src="https://img.incoherency.co.uk/2944/thumb"></a></p>
<p>Before doing any work inside the case, you must <b>unplug the power cable</b> (or at least switch it off at the wall, not on the case of the controller)
and wait for all of the lights inside the controller to turn off. There are some quite large capacitors in the
power supply so it takes a long time for everything to discharge. You must disconnect the power, don't just switch it off on the controller, because there are wires
running from the power socket to the power switch that are still live even when the switch is off.
I got lazy, and then I accidentally leant on the back of the
power socket and zapped myself. Just unplug it at the wall and save yourself the bother.</p>
<p>It's not really necessary to screw the case back together every time you want to quickly test something, but do note that the case is grounded in the top half, but the power supply etc. is connected
to the bottom half, so when the case halves are not connected together the power electronics are not grounded.</p>
<p>If you just need to do software stuff then it is not necessary to power up the rest of the machine. The Arduino is powered over USB so it is running when the USB cable is plugged in even if
the rest of the controller is turned off.</p>
<p>Also note that the spindle motor is powered by AC as well so try not to touch those wires.</p>
<p>Finally, note that the emergency stop button (in both the factory-supplied configuration and the configuration I'm going to suggest here) <b>does not turn off the spindle motor if the
spindle is in Manual mode</b>. In my view, the emergency stop button should immediately cut power to the entire machine, in all circumstances, rather than providing a logic signal to
the motion controller. But that's how it is. Shouldn't be a problem as long as you're aware of it.</p>
<p><h2>1. Install Grbl on an Arduino Uno</h2></p>
<p>Download <a href="https://github.com/gnea/grbl">Grbl</a> and run <tt>make</tt>. If you're on Ubuntu you'll need to install the <tt>avrdude</tt>, <tt>gcc-avr</tt>, and <tt>avr-libc</tt>
packages. I used the Grbl code from <a href="https://github.com/gnea/grbl/commit/eefe2bb95bb7b21ec2bb87e6ab6e20747e1626c4">commit eefe2bb95bb7b21ec2bb87e6ab6e20747e1626c4</a>
which is the latest at time of writing and was published over a year ago. I don't know how likely it is that there will ever be any more changes to Grbl, it seems pretty
complete.</p>
<p>The Grbl instructions say that you can import Grbl into the Arduino IDE and then compile and upload it using the IDE. This does work but means you won't be able
to conveniently change the code because Arduino takes a copy of it and hides it away somewhere. I spent quite some time wondering why my code changes were being
ignored when using the IDE, until I found that compiling on the command line works fine. I'd recommend compiling on the command line. But you probably won't have to
make any code changes unless you want to control the spindle speed using Grbl.</p>
<p>I used <tt>make</tt> to build Grbl, and then this command to upload the binary from <tt>grbl.hex</tt> to the Arduino Uno:</p>
<p><pre><code>$ avrdude -v -patmega328p -Uflash:w:grbl.hex:i -carduino -b 115200 -P /dev/ttyACM0</code></pre></p>
<p>This is different to what is listed in the <a href="https://github.com/grbl/grbl/wiki/Flashing-Grbl-to-an-Arduino">Flashing Grbl to an Arduino</a> instructions. If mine doesn't work for you,
try those instructions instead.</p>
<p>With Grbl installed on the Arduino, you should now be able to download and run the <a href="https://winder.github.io/ugs_website/">Universal G-code Sender</a> and connect it to
the Arduino. You'll want to select 115200 baud. If you connect it to Grbl and you get a bunch of stuff written to the console, it's probably working. You can send "$$" to get it to
dump its configuration. If that works, you're done installing Grbl and can proceed. If you can't get UGS to work for whatever reason but want to test Grbl anyway, you can use the
Serial Monitor in the Arduino IDE. Set it to 115200 baud and send "$$".</p>
<p>I don't know if UGS is the best GUI for Grbl, but it seems to be the most popular. <a href="https://github.com/Denvi/Candle">Candle</a> is another option, but I haven't tried it yet.</p>
<p>You'll want to be able to conveniently connect wires to the Arduino, so I recommend getting a "Grbl shield". There seems to be 2 types of Grbl shield available, one just has screw terminals
for connecting to external stepper drivers, and the other has integrated stepper drivers. You want the one with screw terminals, because the integrated stepper drivers appear not nearly powerful
enough to run the 6040. Get one like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2945"><img src="https://img.incoherency.co.uk/2945/thumb"></a></p>
<p>Or just manage without, up to you. All it does is make it easier to connect wires to the Arduino pins. On the bottom side I found some solder jumpers to select between "traditional" and "PWM"
spindle control mode. Since we're using a non-ancient version of Grbl, we want the "PWM" solder jumpers bridged together.</p>
<p><h2>2. Connect stepper drivers to Grbl</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2946"><img src="https://img.incoherency.co.uk/2946/thumb"></a></p>
<p>At this stage you should probably take photos and write notes so that you can remember exactly how everything was wired to the original USB interface board. Then you can take
the USB board out and throw it away. With all of the wires unplugged from the original board, the emergency stop button is no longer connected to anything, and the case fan
is no longer powered. Neither of these are a problem while testing as long as you are aware of them.</p>
<p>The 6040 CNC has 3x DM542 stepper drivers. Initially the "PUL+" and "DIR+" pins were linked together to +5v, and "PUL-" and "DIR-" were driven by the USB board. I had a bit of trouble getting Grbl
to drive it like this, but after I image searched for something like "arduino dm542 wiring", I found this image:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2932"><img src="https://img.incoherency.co.uk/2932/thumb"></a></p>
<p>I updated the wiring on the stepper drivers so that "PUL-" and "DIR-" were wired together to ground, using the yellow wire to connect to the ground pin on the Grbl shield, and "PUL+" and "DIR+" were
driven by Grbl. This worked straight away, great success.
I left the enable pins ("ENA+" and "ENA-") disconnected like they were before. This seems to work fine, the steppers are just always enabled.</p>
<p>If it helps, you can unplug the screw terminals from the stepper drivers. This makes it much easier to access the screws.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2942"><img src="https://img.incoherency.co.uk/2942/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/2943"><img src="https://img.incoherency.co.uk/2943/thumb"></a></p>
<p>With the stepper drivers plugged in and wired correctly, you should be able to use G-code to move the axes. Either manually send a command like "G0 X5", or use the GUI to jog the axes. If they all
move some distance in some direction when prompted, then you're golden. If not, there is probably some wiring mistake.</p>
<p>Finally we need to configure the direction, steps/mm, max. velocity, and max. acceleration for each axis. Type "$$" in UGS to get the configuration values back out. You can also
read the <a href="https://github.com/gnea/grbl/wiki/Grbl-v1.1-Configuration">Grbl v1.1 Configuration</a> documentation to learn how to set it up.</p>
<p>I went with:</p>
<p><table border>
<tr><th>Setting</th><th>Value</th><th>Meaning</th></tr>
<tr><td>$3</td><td>7</td><td>Step direction invert (bit mask)</td></p>
<p><tr><td>$100</td><td>320</td><td>X Steps/mm</td>
<tr><td>$101</td><td>320</td><td>Y Steps/mm</td>
<tr><td>$102</td><td>400</td><td>Z Steps/mm</td></p>
<p><tr><td>$110</td><td>8000</td><td>X max. speed, mm/min</td>
<tr><td>$111</td><td>4000</td><td>Y max. speed, mm/min</td>
<tr><td>$112</td><td>200</td><td>Z max. speed, mm/min</td></p>
<p><tr><td>$120</td><td>100</td><td>X max. acceleration, mm/sec<sup>2</sup></td>
<tr><td>$121</td><td>100</td><td>Y max. acceleration, mm/sec<sup>2</sup></td>
<tr><td>$122</td><td>100</td><td>Z max. acceleration, mm/sec<sup>2</sup></td>
</table></p>
<p>To update a setting, send something like "$100=320". This gets stored permanently by Grbl (either in EEPROM or flash, not sure) so that it is not lost across a power cycle.</p>
<p>I roughly "binary-searched" to find the max. speed for X and Y axis, and then set the limit to a few thousand mm/min short of what it takes to stall the motors. For the Z axis I deliberately
set the max. speed very low, because a fast-moving Z axis is not particularly useful, and a slow-moving Z axis gives you a chance to hit the emergency stop button before the end mill snaps.</p>
<p>With the steps/mm configured, you should be able to measure that each axis moves the correct distance when jogged. Be wary of trying to tune these values "more accurately", you will likely only
make it worse. For example if you measure that the X axis moves 100.3 mm when you ask for 100.0 mm, it is more likely that your measurement is off (e.g. not perpendicular to the axis) than that
the steps/mm needs adjusting. The correct value for steps/mm is simply a function of the pitch of the leadscrew, the number of steps for a full revolution of the motor,
and the microstepping mode of the driver.</p>
<p><h2>3. Wire up the case fan and emergency stop</h2></p>
<p>At this point the wires powering the case fan are not connected to anything, and we also have spare +24v and ground wires from the DC power supply. I just soldered the fan wires to the power supply
wires, but a screw terminal block would do. 24 volts seems like a lot for a case fan, but it was running off 24v in the factory configuration, so it's probably fine.</p>
<p>The emergency stop button is a "push to make" switch, which means the terminals are connected together when it is pushed in. To make the emergency stop work, just connect one side of the
switch to a ground pin on the Grbl shield, and the other side to the Abort pin on the Grbl shield. This means the Abort pin is pulled to ground when you push the emergency stop
button. Verify that it works: start a long slow movement of the Y axis, for example, and hit the emergency stop. The motor should immediately stop moving, and Grbl should enter an Alarm state
which will be indicated in the GUI.</p>
<p><h2>4. Program the VFD</h2></p>
<p>The spindle speed is controlled by a device called a "PRT-E1500W". This is a VFD or <a href="https://en.wikipedia.org/wiki/Variable-frequency_drive">variable-frequency drive</a>.
The eBay listing for my machine said:</p>
<p><blockquote>Please don’t change the data setting of the VFD if you are not professional technicians, or it might damage the spindle motor.</blockquote></p>
<p>I'm not professional technicians, so I was planning not to change the data setting of the VFD, but when the machine arrived, the VFD was not programmed correctly.
It would not work even in Manual mode. I don't know why.</p>
<p>I followed <a href="https://madexp.com/wp-content/uploads/2018/01/PRT-E1500W-.pdf">these
instructions</a> (<a href="https://incoherency.co.uk/interest/PRT-E1500W-.pdf">mirrored</a>) from <a href="http://madexp.com/">madexp</a> to program the VFD, but
note that after step 1b (D176=1, resetting to
factory settings) you must again set D001=1 to unlock the rest of the settings. You only need to go as far as completing step 3. I don't know what step 4
means. I completed step 5 (display RPM instead of AC frequency) as well because it seems helpful. Steps 6 and beyond appear to be purely Mach3-specific.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2947"><img src="https://img.incoherency.co.uk/2947/thumb"></a></p>
<p>Once you've programmed the VFD correctly, you should be able to select "Manually" mode, press the green "Run" button, and use the knob on the panel to change the spindle speed.
If that works and is enough to satisfy you, then you could quite happily run G-code all day long with Grbl controlling the stepper motors and you manually selecting
the spindle speed.</p>
<p>But I like a challenge, so I wanted Grbl to control the speed.</p>
<p><h2>5. (Optional) Connect VFD to Grbl</h2></p>
<p>Controlling the spindle speed with Grbl is the hardest part. If you just connect the spindle enable pin to the "AVI" pin of the VFD, you will be able to control the speed but only up to half
of the maximum speed. This is because the VFD expects a 10v signal on AVI and the Arduino can only supply 5v. I solved this by using a pair of transistors to let the 5v signal from the
Arduino switch 10v to AVI, so that we can get Grbl to effectively generate a 10v PWM signal from its 5v output. Here's the schematic I came up with:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2941"><img src="https://img.incoherency.co.uk/2941/thumb"></a></p>
<p>I used an S9014 and S9015 transistor because I had them convenient to hand, but you should be able to use anything that can handle 10v. I used 4.7 kOhm base resistors. The schematic should
be fairly self-explanatory. I explicitly labelled emitter, base, and collector because I can never remember which is which. The +10v supply comes from the yellow wire from the VFD, AVI is
the red wire to the VFD, ENA and ground are on the Grbl shield.</p>
<p>I put this together on a little piece of stripboard with some screw terminals:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2937"><img src="https://img.incoherency.co.uk/2937/thumb"></a></p>
<p>And wired it all in, and it worked! I was now able to select the entire range of spindle speeds. I screwed the stripboard to a piece of plywood and glued the plywood to the inside of the case, to prevent
it from flapping around.</p>
<p>To request a spindle speed with G-code, send "M3" to turn the spindle on, followed by (e.g.) "S5000" to request 5000 rpm. "M5" turns the spindle off, as does "S0". "M4" asks for the spindle to turn
backwards. I found that this didn't work, it still turns the spindle forwards, even though I connected the direction pin to the VFD.
I'm not sure I'd ever want to turn the spindle backwards, but maybe that's worth looking into if I ever do.</p>
<p>But there was still a problem: when I requested 5000 rpm the VFD reported that it
was providing about 6400 rpm. If you're fine with that, you can stop now and you're done, you'll just have to have a mental calibration curve for the rpm requested vs. received.</p>
<p>But my view is that this is a job for the computer, not the human, so I wanted to modify Grbl so that it did the calibration curve for me. <a href="https://replicantfx.com/grbl-custom-rpm-to-pwm-mapping-custom-cnc-part-5/">This blog post</a> details modifying the Grbl source to use a custom function for the PWM output. I started trying to derive a function for the curve, but then stumbled
across Grbl's built-in "piecewise linear" function support for non-linear spindle speeds. Just read through the comments in <tt>doc/script/fit_nonlinear_spindle.py</tt> in the Grbl repo and it
tells you how to use it. You'll need scipy (e.g. <tt>python3 -m pip install scipy</tt>) for the calculation, and matplotlib if you want a plot of the fit. Here's what the <tt>fit_nonlinear_spindle.py</tt> output looked like for my machine:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2939"><img src="https://img.incoherency.co.uk/2939/thumb"></a></p>
<p>And then with the suggested changes made to <tt>config.h</tt> and <tt>cpu_map.h</tt>, and the suggested settings for <tt>$30</tt> and <tt>$31</tt>, the VFD-reported spindle speed matches
my requested spindle speed to within a few hundred rpm throughout the entire range. Great success! Remember that if you are modifying any of the Grbl code, you'll need to be compiling on the
command line and not in the Arduino IDE.</p>
<p>Now I just have to learn how to actually use this machine to make parts...</p>
<p><h2>Contact me</h2></p>
<p>If you used this information to convert your 6040 CNC machine to Grbl, please email me to let me know.</p>
<p>Also, if you are confused by any of the information, or if you can provide more accurate information, please let me know that too!
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/6040-cnc-grbl-arduino.html</link>
   <guid>http://incoherency.co.uk/blog/stories/6040-cnc-grbl-arduino.html</guid>
   <pubDate>Wed, 30 Sep 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made an optical inline fuel sensor</title>
   <description><![CDATA[We could automatically detect whether the racing mower is about to run out of fuel
by shining a light through a section of clear fuel hose with a sensor on the other side. The idea is
that when the fuel has disappeared the received light intensity will change, and we can detect this with a microcontroller. We can then turn on an LED on the dashboard to alert the driver
so that he makes a pit stop instead of spluttering to a halt at the opposite end of the track.]]></description>
   <content:encoded><![CDATA[<p>We could automatically detect whether the <a href="https://incoherency.co.uk/blog/tags/lawnmower.html">racing mower</a> is about to run out of fuel
by shining a light through a section of clear fuel hose with a sensor on the other side. The idea is
that when the fuel has disappeared the received light intensity will change, and we can detect this with a microcontroller. We can then turn on an LED on the dashboard to alert the driver
so that he makes a pit stop instead of spluttering to a halt at the opposite end of the track.</p>
<p>I wasn't able to find any examples of previous attempts at something like this, DIY or otherwise, which most likely means it is
a bad solution to the problem. But I made it, and it works. Here's what it looks like:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2925"><img src="https://img.incoherency.co.uk/2925/thumb"></a></p>
<p>If you want to see a video of it in action, I have <a href="https://www.youtube.com/watch?v=y3l_yfWQwT8">this video</a> but
it's not a very good video.</p>
<p>You can get the Arduino code and housing CAD files on <a href="https://github.com/jes/fuelsafe">my github project</a>.</p>
<p>This is a good design for the fuel sensor, in my opinion, because the fuel is entirely contained within off-the-shelf parts that are designed
to contain fuel and never touches any custom parts, which means the chances of causing a leak or fire are low. The bad part about this
design is that it does not give us an easy way to configure a threshold at which the warning light comes on: it just comes on once the fuel
level has dropped below the position of the sensor. But I think this should still give us a lap or two of warning, because we still have the fuel in the rest
of the hose, the fuel filter, and the float bowl.</p>
<p><h2>Experiments</h2></p>
<p>I didn't want to commit to making the entire thing before discovering whether or not it would even work. For example, it's
quite possible that the brightness detected at the photoresistor would be within the same range regardless of the presence or
absence of fuel.</p>
<p>I set up a short length of clear hose with some water in it, and 3d printed a little ring that would allow me to position
an LED and photoresistor at different relative angles. I used water because I didn't have any convenient petrol to use, and
water is clearer than petrol, so if it works with water it should definitely work with petrol.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2897"><img src="https://img.incoherency.co.uk/2897/thumb"></a></p>
<p>I measured the "reading" from the photoresistor by setting up a voltage divider with the photoresistor on one side and a 4.7 kOhm resistor
on the other. I chose a green LED because I read that photoresistors are most sensitive to green light.</p>
<p>My initial thought was to
shine the LED straight through the hose, but I thought that refraction and reflection might provide interesting effects and
we might get a different "signal strength" if we changed the angle, which is why I tested 4 angles. As it turns out, we do:</p>
<p>(As an aside: both of these charts have the angles in the correct order, but at incorrect labels; the actual angles tested were 60&deg;,
100&deg;, 140&deg;, and 180&deg;, but I had a <a href="http://catb.org/jargon/html/T/thinko.html">thinko</a> each time when writing the data in the spreadsheets).</p>
<p>For the first test, I didn't even switch off the lights in the room. I just moved the ring up and down between water and air, and recorded the rough range of
measurements at each position. The "error bars" here show the range of values I recorded.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2896"><img src="https://img.incoherency.co.uk/2896/thumb"></a></p>
<p>It turns out that any of the possible positions appears to have sufficient discriminatory power to work as the actual sensor, as they all had
no overlap in readings between the "with fuel" and "without fuel" conditions. I repeated the test with the lights in the room switched off,
and got similar results:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2901"><img src="https://img.incoherency.co.uk/2901/thumb"></a></p>
<p>It's interesting that somewhere between 140&deg; and 180&deg;, the brightness "with fuel" goes from being lower than "without fuel" to being higher.</p>
<p>From these results, I concluded that the 60&deg; angle is the best choice because it has the widest gap in sensor readings between the "with fuel" and
"without fuel" conditions.</p>
<p><h2>Housing</h2></p>
<p>I wanted to run this off an <a href="https://www.microchip.com/wwwproducts/en/ATtiny85">ATtiny85</a> microcontroller, because they are small
and cheap, and I haven't managed to use one for anything before. Using an ATtiny85 means we need to expose a 6-pin programming header. It took
me quite a long time to come up with a neat way of packaging all the parts so that:</p>
<p><ul>
<li>the fuel hose runs straight through</li>
<li>the fuel hose does not fall out</li>
<li>the electronics can easily be potted in without spilling resin everywhere</li>
<li>the programming header is protected from damage</li>
<li>the device is firmly held and not just flapping around loose</li>
<li>the parts 3d print without excessive support material</li>
</ul></p>
<p>I eventually settled on this, which looks obvious in hindsight, but was hard for me to think of:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2929"><img src="https://img.incoherency.co.uk/2929/thumb"></a></p>
<p>The fuel hose runs through the cylindrical hole at the bottom. The small end cap prevents ambient light from leaking up the length of the hose (there'll
be one at each end, but I only modelled one as they are both identical).
The LED and photoresistor get glued into the little holes that meet the large cylindrical hole. The circuit board sits in the cavity at the top.
The flat lid piece screws down into the housing to protect the exposed programming header and provide a flat surface to mount against the chassis
of the mower, and the cut-outs through the bottom allow cable ties to strap the device in place.</p>
<p>I also added a small logo because I was feeling fancy:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2930"><img src="https://img.incoherency.co.uk/2930/thumb"></a></p>
<p>I 3d-printed this in 3DXTech's CarbonX Nylon. Pretty much any material would do as these parts are not really under any load,
but carbon fibre gives you automatic racing credentials so it was the obvious choice.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2910"><img src="https://img.incoherency.co.uk/2910/thumb"></a></p>
<p>The writing is not as easy to read as I had hoped.</p>
<p>You can see there that I have already pushed the clear fuel hose into the hole. This was an extremely tight fit so I am not at all concerned
that it might fall out.</p>
<p>The screw hole does not have printed threads, I just cut a thread in it by hand using an M3 screw.</p>
<p><h2>Electronics</h2></p>
<p>I designed the circuit board in tandem with the housing, because the plan for each one informs the design of the other. Here is what I came up
with as a "schematic":</p>
<p><a class="img" href="https://img.incoherency.co.uk/2927"><img src="https://img.incoherency.co.uk/2927/thumb"></a></p>
<p>In addition to being an almost-adequate schematic, it also doubles as a copper stripboard layout, which is why it is laid out so strangely
and also why it has some crosses, marking where traces need to be cut. The A,B,C,D labelled connections are:</p>
<p><ul>
<li><b>A</b>: output signal and GND</li>
<li><b>B</b>: to photoresistor next to hose</li>
<li><b>C</b>: input power and GND</li>
<li><b>D</b>: to LED next to hose</li>
</ul></p>
<p>It uses an LM7805 to regulate the input voltage down to 5v. There is an arbitrary smoothing capacitor across the output of the LM7805 for
good measure. I picked a small ceramic capacitor when I put it together, but I have no idea how much good it will do. The 6-pin
connector at the top is a programming header for the ATtiny85.</p>
<p>Here's a picture of the board with the "C" and "D" wires in place, but "A" and "B" not yet, and also the LM7805 hadn't arrived yet:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2902"><img src="https://img.incoherency.co.uk/2902/thumb"></a></p>
<p>This project could have been quite a bit smaller if I had used SMD components on a custom PCB instead of through-hole components on copper
stripboard. I have never made anything with SMD components but last time I showed <a href="https://www.stavros.io/">Stavros</a> one of my
projects he remarked "you really like through-hole, huh?". I think it is probably about time I learnt how to do SMD. Maybe next time.</p>
<p>The software running on the ATtiny85 is very simple. It just runs in an infinite loop, comparing the voltage on an analogue pin to a threshold value,
and switching the output signal on if the threshold is exceeded, and off otherwise. This could be replaced with a <a href="https://en.wikipedia.org/wiki/Comparator">comparator</a>
quite easily. I didn't do it that way, for two reasons: firstly because software makes more sense to me than electronics, and secondly because the microcontroller can be
reprogrammed with whatever logic we can think of in the future, and the comparator can't. For example, if we find that the signal is too noisy, it is easy to
add some smoothing logic in software, but it's not easy to add extra components to the circuit board.</p>
<p><h2>Assembly</h2></p>
<p>With housing and electronics ready, we can start putting this together. I epoxied the LED and photoresistor into their holes with clear epoxy, rather than just letting
the potting resin hold them in place, because I was planning to use black polyurethane resin for the potting, and I was concerned it might inhibit light
if it seeps around to the front of either the LED or the photoresistor.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2915"><img src="https://img.incoherency.co.uk/2915/thumb"></a></p>
<p>Then push the circuit board into its cavity:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2916"><img src="https://img.incoherency.co.uk/2916/thumb"></a></p>
<p>Then we just have to pour the resin. I was disappointed to find that the bottle of hardener for my polyurethane resin has all crusted up and set solid, so I
wasn't able to use it. I couldn't be bothered waiting for some new resin to arrive, so instead I used the extremely soft 2-part silicone resin that
I bought for making the tyres on the <a href="https://incoherency.co.uk/blog/stories/wedge-of-glory.html">antweight combat robot</a>. This is a bad choice of potting compound because it
is not very good at preventing sharp objects from penetrating it, and it does not stick to stuff. But with the lid on the housing, I think it'll be fine.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2917"><img src="https://img.incoherency.co.uk/2917/thumb"></a></p>
<p>Protip: if you're potting some electronics, and you want to expose a pin header, use a male header instead of a female one, otherwise
it might <a href="https://incoherency.co.uk/blog/stories/scooter-speedo.html">fill up with resin</a>.</p>
<p>After the silicone dried, I screwed the lid on, and the assembly was complete:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2918"><img src="https://img.incoherency.co.uk/2918/thumb"></a></p>
<p>I switched it on and took this picture showing the green light inside the hose, it looks quite cool:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2924"><img src="https://img.incoherency.co.uk/2924/thumb"></a></p>
<p>And then I waited for the brass hose barbs to arrive. I could have 3d printed the hose barbs, but I thought that was a bad idea. The natural print orientation to ensure
a good seal with the hose would be to have the hose barb standing on end, but this would mean that there is only a very small surface area for layer adhesion between the print layers, and
I don't think it would take a lot of force to snap a hose barb 3d printed in this manner. A snapped hose barb in the fuel line would be a pretty catastrophic failure, so I thought it
best to use metal ones. I could have made some on the lathe but that's a hassle and off-the-shelf ones are not very expensive anyway.</p>
<p><h2>Calibration</h2></p>
<p>I was originally going to calibrate the sensor by having it write the photoresistor measurement over USB serial and then pick a threshold value that looks to be about halfway between
the "with fuel" and "without fuel" values. Unfortunately, the ATtiny85 does not provide USB serial.</p>
<p>I instead made it write the measured sensor reading out using <tt>analogWrite()</tt> to one of the pins exposed on the programming header, so that I can then measure it with a multimeter.
This worked fine, and I found that it measured 1.6v when there was water in the hose, and 2.6v when there was not. The ATtiny85 has a 10-bit ADC, which means 0v become 0 and 5v becomes 1023.
Our threshold wants to be halfway between 1.6 and 2.6 volts, so 1024 * 2.1 volts / 5 volts = 430.</p>
<p>I wired up an Arduino Nano on a piece of copper stripboard with a female 6-pin header on it, to allow convenient programming of the ATtiny85:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2931"><img src="https://img.incoherency.co.uk/2931/thumb"></a></p>
<p><h2>Conclusion</h2></p>
<p>Probably I should have been a bit less impatient and ordered some more polyurethane resin instead of making do with the silicone.</p>
<p>Apart from that, I think this looks like a great success. Unfortunately there is not likely to be any lawnmower racing this year due to the coronavirus.
Hopefully the 12 hour is back next year and I'll be able to report on whether the device works or not.</p>
<p>I still need to weld a metal bracket in a convenient place on the chassis to cable tie the sensor to, but that shouldn't be a problem. I wanted to build a new fuel tank mount
anyway, due to the incident with the fuel tank <a href="https://incoherency.co.uk/blog/stories/blmra-12-hour-2019.html">falling off at last year's race</a>.</p>
<p>If you want to build a FuelSafe device, you should be able to find everything you need in the <a href="https://github.com/jes/fuelsafe">github repo</a>. I highly recommend the waterproof
connectors that I have used. I believe they are a generic no-name product. They are widely available on eBay, at any rate. Please email me if you have any questions or need any help.</p>
<p>Cheers.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/inline-fuel-sensor.html</link>
   <guid>http://incoherency.co.uk/blog/stories/inline-fuel-sensor.html</guid>
   <pubDate>Mon, 28 Sep 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Miscellaneous thoughts on making stuff</title>
   <description><![CDATA[This is just a selection of points related to manufacturing that are grouped into one post for
no other reason than that I don't have enough on each one individually, but wanted to write
about them before I forget.]]></description>
   <content:encoded><![CDATA[<p>This is just a selection of points related to manufacturing that are grouped into one post for
no other reason than that I don't have enough on each one individually, but wanted to write
about them before I forget.</p>
<p><h2>Are our 3d parts constrained by our 2d paper?</h2></p>
<p>Before CAD-modelling or hand-making a part, it is almost always transformed from an abstract model in the
designer's mind into a sketch on the designer's paper. This helps clarify thinking, ensure that moving parts
won't crash into each other, etc.</p>
<p>A simple part can be sketched from just one view. More complex parts can have top, front, and side views,
as well as a 3d projection, cross sections, and whatever other views are useful.</p>
<p>A part gets harder to sketch as more views are required, and more effort is required
of the designer to ensure that all of the views are consistent with one another. It is
therefore natural to contain as many features as possible within a single view.</p>
<p>I contend that this results in <b>a natural preference for features which lie in a common plane</b>, even when
the optimal solution to the problem has no such constraint.</p>
<p>How much does this preference for planar features restrict the space of designs that humans can come up with?</p>
<p>What would we gain if it were easier to explore more of the design space?</p>
<p>How can we make the design space easier to explore?</p>
<p><h2>Why so many 3d printing designs suck and why that's a good thing</h2></p>
<p>If you spend some time browsing <a href="https://www.thingiverse.com/">Thingiverse</a>
then you might notice that some of the parts are designed very strangely. Parts that have sharp and square
edges where rounded edges would look neater, thinner or thicker than appropriate, strength in the wrong places, inappropriate
fasteners, and so on.</p>
<p>Your first reaction might be "this is clearly bad, these people are no good at designing things". I think the opposite way
of looking at it is more useful: <b>people with no training or experience are now able to design and
produce parts that successfully solve their problems</b>. It's not that designing for 3d printing results in worse parts,
it's that the barrier to entry for design of working parts is <i>much</i> lower than it ever has been in the past. And I think
that is a good thing.</p>
<p><h2>How fast can you 3d print stuff?</h2></p>
<p>An FDM printer has to raise the temperature of the plastic it prints from 20&deg;C to 200&deg;C. The specific heat capacity of PLA
is 1800 J/kg.K (<a href="https://www.sd3d.com/wp-content/uploads/2017/06/MaterialTDS-PLA_01.pdf">source</a>). To print a 1 kg part,
we need to raise the temperature of 1 kg of PLA by 180&deg;C, which we know from the specific heat capacity will take 1800 * 180 = 324 kJ.</p>
<p>We can get 230 volts * 13 amps = ~3 kW from the AC supply. 1 W = 1 J/sec, so we can expect to bring our kilogram of PLA up to the printing
temperature in 324 / 3 = <b>~100 seconds</b>.</p>
<p>In practice, today, printing a kilogram of PLA on a home machine will take well over 24 hours, so there is potentially a lot of room for improvement here. Current home-level 3d printers
can't spend all 3 kW on heating the plastic because of losses in:</p>
<p><ul>
<li>heating the bed</li>
<li>running the stepper motors</li>
<li>running the fans</li>
<li>running the microcontroller and display</li>
<li>heat leakage from the hot end that doesn't go into the plastic</li>
</ul></p>
<p>The fans, microcontroller, and display should be negligible, so we only need to worry about heating the plastic and the bed and driving the stepper motors. With "sufficient" insulation,
keeping the bed hot for the duration of the print should tend towards 0 energy usage, because once we've raised the temperature at the start, we don't want to put any more energy into it,
we just want it to stay where it is. That means that in the limit case, we only need to heat the extruded PLA and run the motors, and everything else in the machine can use the last 10% or so of spare
energy.</p>
<p>In addition to constraints on how fast we can heat the plastic, we also have constraints on how fast we can move the motors. I suspect that in practice this is currently the bigger
constraint. One way to get around this is to use a larger nozzle, fatter extrusions, and taller layers, so that you can get more plastic out for any given movement of the motors, although
this does impact the quality of the parts you can print. Another option is to work on moving the motors faster. This requires more powerful motors (and therefore more energy usage), and
also a stiffer machine so that it doesn't wobble under high acceleration.</p>
<p>But fitting a larger nozzle and a stiffer frame doesn't impact energy usage, so we can take these as a given. I expect that if somebody created a 3d printer that optimised the ratio
of motor power usage and hot end power usage to maximise printed speed, we would be able to get close to at least an order of magnitude away from the theoretical optimum, which would mean that <b>printing 1 kg of PLA within 15 minutes
on a home machine is within the bounds of plausibility</b>, provided you're willing to trade off a bit of quality for speed.</p>
<p>Whether this is a project worth pursuing is not so clear. The typical home user isn't really time-sensitive when it comes to 3d printing, particularly if reducing print times
would make the machine more expensive. Personally, I deliberately run the printer slower than it can possibly go because it results in higher-quality parts. The people who are most sensitive to printing
speed are probably mass-producing things, which means they're probably not using 3d printing in the
first place. But even if they <i>are</i> 3d printing, they probably have a lot more than 3 kW at their disposal, so the attainable performance is even higher.</p>
<p><h2>What material would you make stuff out of?</h2></p>
<p>In prehistory, ancient man built things out of sticks and stones. This is not because they're particularly good materials, but merely because they were convenient to acquire and
easy to work with. Since then, we've learnt to work with ceramics, glasses, metals found in the ground, man-made alloys, plastics, composites like carbon fibre-reinforced plastic, and
probably a lot more stuff I don't even know exists.</p>
<p>We have a wide array of materials available today, but we're still largely constrained to working with materials that are convenient to acquire or produce, and easy to work with. This
does not necessarily result in optimal parts.</p>
<p>If we had omnipotent levels of control over where we placed the fundamental particles that make up our parts, I don't think we'd end up with materials that look much like what we have today. You
could imagine parts that aren't even made of identifiable atoms at all! Just quarks arranged in ways that optimise whatever material properties are useful in any given application. That would allow
us to achieve the actual <i>optimal</i> levels of lightness, stiffness, strength, conductivity, heat resistance, and so on, without any constraint imposed by the specific elements that happen to be
easy to dig out of the crust of the earth, or the processes that we can apply to them (which is mainly glorified versions of heating them up and smashing them apart). I think <a href="https://en.wikipedia.org/wiki/Graphene">graphene</a> offers a glimpse into what could be possible here, except we only even know about graphene
because it is comparably easy to manufacture! There are surely much more advanced possibilities still out of reach.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/making-stuff.html</link>
   <guid>http://incoherency.co.uk/blog/stories/making-stuff.html</guid>
   <pubDate>Tue, 15 Sep 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Progress on my Godot racing game for Oculus Quest</title>
   <description><![CDATA[I've made some decent progress on the Oculus Quest racing game. I think it is already the most realistic driving simulator for the Quest, but
that's not a very high bar as there are not any real competitors.]]></description>
   <content:encoded><![CDATA[<p>I've made some decent progress on the Oculus Quest racing game. I think it is already the most realistic driving simulator for the Quest, but
that's not a very high bar as there are not any real competitors.</p>
<p>You can play the game now, if you want. It's <a href="https://sidequestvr.com/app/1403/ghost-racing-vr-wip">available on SideQuest</a>. I'd warn you that it's not
much of a game: all you can do is drive the car around the track over and over again, or drive through the car park when you get bored of that. It does time your laps
and show a ghost car of your best time so far, but it doesn't save your best lap for future.</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/M1xzSrjKYhY?start=13" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>The game is currently called "Ghost Racing VR", but I think this is a bad name, not least because I discovered there is <a href="https://www.ghostracing.com/">already a game called Ghost Racing</a>. So
I'm on the lookout for a better name. I want the word "racing" in it so that it definitely shows up in SideQuest searches for "racing", but I also don't want the title to imply that you are racing
against anything other than a ghost of yourself. Tricky one.</p>
<p><h2>Facebook</h2></p>
<p>Oculus <a href="https://www.oculus.com/blog/a-single-way-to-log-into-oculus-and-unlock-social-features/">have announced</a> that as of October this year, everyone using an Oculus device
for the first time will need to link it to a Facebook account, and all existing Oculus device users will have to do so in 2 years' time. On a device they already bought and paid for and own!
This seems unreasonable, and I would now advise anyone who
is thinking of buying an Oculus product not to buy one. The Facebook side of things was always concerning (what with Facebook basically having cameras and microphones inside my house),
but it was previously quite easy to ignore. Not so much now :(.</p>
<p><h2>Track</h2></p>
<p>The track I was working with <a href="https://incoherency.co.uk/blog/stories/oculus-quest-car-racing.html">last time</a> was created with the "track_base" scene from Bastiaan Olij's <a href="https://github.com/BastiaanOlij/vehicle-demo">Vehicle Demo</a> project. The problem with this is that it's hard to export as a triangle mesh to help with adding surrounding scenery.</p>
<p>After that, I tried making some tracks in Blender. You can see a track I made in Blender <a href="https://www.youtube.com/watch?v=LLnidRJkD7A">in this clip</a>, albeit with no texturing.
I was starting to get the hang of the process
of drawing a track segment, drawing a Bezier curve, extruding the track segment through the curve using the Array and Fit Curve modifiers, then applying the modifiers to edit it as a triangle mesh, and
then exporting with glTF to import into Godot. I was still struggling with what to do in the event that I applied the modifiers too early and wanted to go back to editing the curve. It seems there is just
no option here: once you apply the modifier, you're stuck with whatever you've got. I much prefer FreeCAD's method of allowing you to go back to earlier steps and change the parameters.</p>
<p>I didn't need to learn any more Blender, however, as a chap named Quy Nguyen emailed me instructions for <a href="https://incoherency.co.uk/blog/stories/assetto-corsa-race-tracks-in-godot.html">importing Assetto Corsa race tracks
into Godot</a>. This is an approach I hadn't even considered, and it worked really well. It has saved an enormous amount of effort, and the upshot is that I now have a perfectly passable copy of
<a href="https://en.wikipedia.org/wiki/Cadwell_Park">Cadwell Park</a>, created by <a href="https://www.racedepartment.com/downloads/cadwell-park.11507/">Terra21 and Jim Lloyd</a>, which I can drive
around in virtual reality. This is already significantly better than I ever thought the game would be. Releasing <a href="https://en.wikipedia.org/wiki/Release_early,_release_often">early and often</a>
is definitely the way to go, because other people see what you're doing, get in touch, and help you. So: if you read something in this post and think it's wrong, or think you can help, please let me know!</p>
<p><a class="img" href="https://img.incoherency.co.uk/2869"><img src="https://img.incoherency.co.uk/2869/thumb"></a><br></p>
<p><h2>Physics</h2></p>
<p>Starting from Godot's <a href="https://docs.godotengine.org/en/3.2/classes/class_vehiclebody.html">VehicleBody</a> means a lot of the physics is already taken care of, which saves a lot of work.</p>
<p><h4>Limited-slip diff</h4></p>
<p>I did a basic simulation of a <a href="https://en.wikipedia.org/wiki/Limited-slip_differential">limited-slip diff</a> as follows:</p>
<p><pre><code># limited-slip diff: apply more power through the wheel with the least grip, with at least min_diff_bias of total going to each wheel
var total_force = throttle_val * current_engine_force
var diff_bias = 0.5
if ($left_rear.get_skidinfo() > 0 || $right_rear.get_skidinfo() > 0):
    diff_bias = $left_rear.get_skidinfo() / ($left_rear.get_skidinfo() + $right_rear.get_skidinfo())
if (diff_bias < min_diff_bias):
    diff_bias = min_diff_bias
if (diff_bias > (1 - min_diff_bias)):
    diff_bias = (1 - min_diff_bias)
$left_rear.engine_force = lerp(0, total_force, 1 - diff_bias)
$right_rear.engine_force = lerp(0, total_force, diff_bias)</code></pre></p>
<p><tt>throttle_val</tt> ranges from 0 to 1, to indicate throttle position. <tt>current_engine_force</tt> gives us the engine force available at current RPM and maximum throttle. <tt>min_diff_bias</tt> is
a configuration value for the minimum proportion of engine force that must go to each wheel (set to 8%). <tt>diff_bias</tt> is computed by weighting the engine force to each wheel according to the proportion that
the wheels are skidding. <tt>lerp(a, b, t)</tt> is equivalent to <tt>a + (b - a) * t</tt>, i.e. linear interpolate from a to b, at time t (t ranging from 0 to 1).</p>
<p>This is not a great simulation, but it's better than both the "locked diff" that we got by default, and the "open diff" that we got without the <tt>min_diff_bias</tt>. Problems are that it
basically assumes that there is 0 inertia in both the wheels and the diff, so it reacts <i>immediately</i>, instead of smoothly. It also acts exactly like an open diff up until the point where the
<tt>min_diff_bias</tt> is reached, whereas in reality I think it should reach the limit smoothly instead of a hard stop. It drives well enough though, so I don't really plan to change it. Using "force"
instead of "torque" is a VehicleBody quirk. The conversion from torque to force is performed earlier on, in the computation of <tt>current_engine_force</tt>.</p>
<p><h4>Brake bias</h4></p>
<p>Brake bias is easy:</p>
<p><pre><code>var front_brake = delta * (brake_val * MAX_BRAKE_FORCE * front_brake_bias)
var rear_brake = delta * (brake_val * MAX_BRAKE_FORCE * (1 - front_brake_bias))
$left_front.brake = front_brake
$right_front.brake = front_brake
$left_rear.brake = rear_brake
$right_rear.brake = rear_brake</code></pre></p>
<p><tt>brake_val</tt> is the brake "pedal" position.</p>
<p>The only surprising part here is that we need to multiply by <tt>delta</tt> to get the braking values. <tt>delta</tt> tells us how much time has passed since the last physics
timestep (which would be 1/72 of a second in the
normal case). For some reason the VehicleBody wants forces for engine force, but impulses for braking force.</p>
<p><h4>Clutch</h4></p>
<p>Currently the clutch "simulation" lets the game down. Basically the clutch slips perfectly to hold you at precisely 1000 rpm (but magically still with full engine braking???) until you are moving fast enough
for the engine to be running faster than 1000 rpm, and then the clutch is fully disengaged. This also means there's hardly any torque when pulling away from a standstill, because you're not allowed anything
more than 1000 rpm until the clutch is fully engaged. The only time this isn't true is when you're in neutral, when a completely different model is applied, which
allows you to rev up the engine semi-convincingly even though you're not moving. I need to work on the clutch model.</p>
<p><h4>Grip</h4></p>
<p>You can read about how grip is supposed to work in the "Magic Formula" parts of Brian Beckman's <a href="http://autoxer.skiblack.com/phys_racing/contents.htm">Physics of Racing Series</a>. Basically
optimal grip is achieved at some small level of slip, and then grip drops off as the tyre starts to slip further. This should be calculated independently for lateral and longitudinal slip.</p>
<p>VehicleBody doesn't allow us to set separate friction for lateral and longitudinal grip, so I just compute a single friction value for each tyre, which applies to both. I based it on this chart
from the Wikipedia page on <a href="https://en.wikipedia.org/wiki/Hans_B._Pacejka">Hans Pacejka</a>, who invented the Magic Formula:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2866"><img src="https://img.incoherency.co.uk/2866/thumb"></a><br>
<i>(Image from <a href="https://en.wikipedia.org/wiki/Hans_B._Pacejka">Wikipedia</a>.)</i></p>
<p>In reality the curve should be very much dependent on the tyre temperature, tyre pressure, tyre wear, road surface type, weather conditions, etc., but I just have a single hard-coded approximation
made of linear sections that looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2867"><img src="https://img.incoherency.co.uk/2867/thumb"></a><br></p>
<p>(The reason the friction force starts out at the basic level instead of at 0 is so that the tyre doesn't feel oddly slippery at really low speeds. In practice Pacejka's formula is more correct because it is
impossible for the tyre to provide more force than is being pushed against it, but in the game we're basically setting the tyre friction 1 frame behind where we want to be, which makes it feel
slippery if we set it too low. At low levels of slip we could just give the tyre <i>infinite</i> grip and it wouldn't make any difference, so it's fine as long as we don't give it too little).</p>
<p>It works quite well at giving the feeling of being able to drive up to the limit of the tyre, and then "falling off" as you exceed the grip limit. It does <i>not</i> work well at giving much feedback
as to how close you are to the limit. You can see that on the Wikipedia chart the curve starts to round off before peak friction is achieved, which would let you know you're approaching it.
Maybe I need to do something like that in the game.</p>
<p>Another hack I have in the game is to increase the grip of the rear tyres by 9% compared to the front. I found that the car is quite prone to
<a href="https://en.wikipedia.org/wiki/Lift-off_oversteer">lift-off oversteer</a>. I
tried to fix this with suspension settings but couldn't sort it out. Increasing the grip at the rear is not really realistic, but helps stabilise the car on corner entry. 9% is a level where the car doesn't
feel like it either understeers or oversteers too much, it seems like a good balance to me.</p>
<p><h4>VehicleBody limitations</h4></p>
<p>VehicleBody has several annoying limitations. Some of them would be easy to fix, if only VehicleBody were implemented in GDScript instead of C++. As it stands, I think making changes to VehicleBody
implies recompiling all of Godot, which I looked at but seemed too much hassle. It might be worth porting VehicleBody to GDScript so that it can be changed more easily, but I think I'd rather just
work around its limitations for the time being.</p>
<p>VehicleBody calculates the weight on each corner of the car, because it needs to know this for the physics, but it does not expose this information in any way. The best I have come up with is working
backwards from the suspension position to try to approximate the weight. This would be easy to fix, it just needs to expose the value that it has already calculated.</p>
<p>VehicleBody doesn't have a way to set separate friction values for lateral and longitudinal grip. It kind of bodges this internally by reducing all longitudinal impulses by half, but I'd prefer to
have more control over it. I think just exposing a way to change the reduction of longitudinal forces at runtime (from "half" to a value of my choice) would go a long way towards helping with this.</p>
<p>VehicleBody does not correctly calculate wheel RPM in the event that the wheel is slipping. It calculates the wheel RPM by measuring how far the wheel has moved and dividing by the wheel circumference,
which is not correct when the wheel is not purely rolling. This makes working backwards from wheel RPM to inform engine RPM problematic, because the engine RPM suddenly drops, instead of rising,
as soon as the wheels start slipping. I have some bodges around this but they don't work well. This definitely needs work, and unfortunately I don't know what the solution would look like.</p>
<p>VehicleBody <i>seems</i> to completely ignore the friction setting of the surface that the wheel is touching. This is a problem because it means the grass is just as grippy as the tarmac and there is
seemingly nothing I can do about it. The VehicleWheel documentation says that the friction of the tyre is "combined with the friction setting of the surface the wheel is in contact with", but I have
not observed this behaviour. This definitely needs looking at.</p>
<p>VehicleBody does not have any obvious way to adjust the <a href="https://en.wikipedia.org/wiki/Moment_of_inertia">moment of inertia</a> of the car. I suspect this is why the car is so prone to
lift-off oversteer: it basically acts like a point mass that only has tyres preventing it from spinning, whereas in real life cars are hard to spin because their weight is not all concentrated in
the centre. This could do with looking at, but just increasing the grip of the rear tyres is probably good enough for now.</p>
<p><h4>A RigidBody vehicle</h4></p>
<p>I said last time that I didn't see why I couldn't just create a car by adding a RigidBody for each wheel, and a damped spring joint connecting each wheel to the body. I did try this, but it did not
work very well. Whenever a wheel rolled over a join between 2 triangles on the surface of the road (and therefore touched 2 triangles simultaneously, briefly) it acted weirdly and made the car
jump around. Also, the suspension kind of behaved like it was acting on the centre of mass of the car rather than on the corner it was connected to (?). A force upwards on any corner would raise
the entire car, parallel, rather than tilting it. I'm not really sure why, but I learnt enough to decide that I haven't learnt enough to make it work this way, so I'm going to be sticking
with VehicleBody for now.</p>
<p><h2>Sound</h2></p>
<p>I've added some basic sounds to the game, and they add a <i>lot</i> compared to driving around in total silence. So far I've got tyre squeal sounds, a clunk when you change gear,
and 2 types of engine sound. The engine sound is possibly too quiet, especially at low throttle positions, but it'll do for now.</p>
<p><h4>Tyre squeal</h4></p>
<p>There's an <a href="https://docs.godotengine.org/en/3.2/classes/class_audiostreamplayer3d.html">AudioStreamPlayer3D</a> node positioned (roughly) at the contact patch of each wheel. When Godot's <a href="https://docs.godotengine.org/en/3.2/classes/class_vehiclewheel.html#class-vehiclewheel-method-get-skidinfo"><tt>VehicleWheel.get_skidinfo()</tt></a> tells us that the wheel has broken grip,
the audio starts playing a looped sample of tyre squeal, with volume increasing as the amount of skid increases, and frequency decreasing as the amount of skid increases. The "amount of skid"
is calculated based on <tt>get_skidinfo()</tt>, the speed of the car, and the approximate amount of weight on that corner.</p>
<p>I was going to include a code sample but it's really long and confusingly-written. The text description is easier, I promise.</p>
<p><h4>Engine noises</h4></p>
<p>There's an AudioStreamPlayer3D node positioned at the end of the exhaust, and one positioned under the bonnet. I have 2 samples of Caterham engine noise, one with the throttle open and
one with it closed, and they are played as follows:</p>
<p><pre><code>func update_audio_db(audio_node, new_db, rate):
    audio_node.unit_db = audio_node.unit_db * (1-rate) + new_db * rate</p>
<p>func update_engine_sound(engine_rpm, throttle_val):
    if (throttle_val < 0.01):
        throttle_val = 0.01
    update_audio_db($EngineAudio, log(throttle_val)-1.0, 0.5)
    $EngineAudio.pitch_scale = engine_rpm / 4100.0
    update_audio_db($EngineThrottleAudio, 2.0*log(throttle_val)-1.0, 0.5)
    $EngineThrottleAudio.pitch_scale = engine_rpm / 5000.0</code></pre></p>
<p>Both the "ordinary" and "on-throttle" samples increase in amplitude as the throttle is opened, but the "on-throttle" sample more so.</p>
<p>4100 RPM and 5000 RPM are the approximate engine speeds in the corresponding samples.</p>
<p><tt>update_audio_db()</tt>'s smoothing of audio volume is not correct given that the unit is
<a href="https://en.wikipedia.org/wiki/Decibel">decibels</a>, but it's adequate. All it is really doing is making sure the audio doesn't
instantly change volume when you squeeze the throttle trigger, because that sounds weird.</p>
<p>The engine sounds in the game are not that great. The engine always sounds very smooth, across the entire rev range and with every throttle position. I think I want to add some crackle sound effects when
RPM are dropping rapidly, get a more throaty-sounding "on-throttle" sample, and get several more interesting exhaust samples to fade between at different RPM ranges.</p>
<p><h2>Graphics</h2></p>
<p><h4>Performance</h4></p>
<p>The Cadwell Park track had about 1.5M vertices at first. I reduced this down to more like 400k by getting rid of the 3-dimensional grass, spectators, vehicles parked alongside the circuit, most of the
buildings, and half the trees. More than 50% of the remaining vertices now are in the tyre walls, because every single tyre in every single wall is modelled as a separate 10-sided cylinder, which adds up
fast considering they line almost the entire circuit on both sides and are stacked 4-high. I probably want to either delete the less-important tyre walls, or replace them with something simpler. Not
quite sure on the easiest way to do that, but something to keep an eye out for.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2870"><img src="https://img.incoherency.co.uk/2870/thumb"></a><br></p>
<p>I've also turned off almost all of the graphical enhancements in Godot, and the result is that the game stays above 50 fps for the entire lap, even with
<a href="https://developer.oculus.com/documentation/native/android/mobile-ffr/">foveated rendering</a> turned off. Really we'd be aiming for a stable 72 fps at all times, which I think is
probably achievable if I can sort out the tyre walls.</p>
<p><h4>Things to improve</h4></p>
<p>It would probably be worth spending a bit more of the polygon budget on the cockpit of the car, given that it takes up about a quarter of the field-of-view and is visible the entire time. Also
a more appropriate (and higher-res) skybox would help, because Cadwell Park is actually not nestled in the foothills of the Rocky Mountains.</p>
<p><h4>Weird bugs</h4></p>
<p>The foveated rendering appears to cause some issues with the depth buffer.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2871"><img src="https://img.incoherency.co.uk/2871/thumb"></a><br></p>
<p>You can see that in the areas where the resolution is reduced (i.e. at the edge), you can see "through" the road to the skybox behind. I do not know why this happens. I don't see why reducing the
resolution would have this effect. It only seems to happen on things that are far away. I tried reducing the distance to the <a href="https://en.wikipedia.org/wiki/Clipping_(computer_graphics)">far plane</a>, and didn't observe the effect at all. Unfortunately the far plane
needs to be quite far away else you see trees in the distance being clipped in and out of view, which looks bad.</p>
<p>I have also observed a "flickery grey rectangle" that sometimes appears in the middle of the view and makes it impossible to continue. There is no way to get rid of it, you just need to close and
restart the game.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2872"><img src="https://img.incoherency.co.uk/2872/thumb"></a><br></p>
<p>It is possible that this is another consequence of the depth
problem, and that this time you're actually seeing beyond the <i>skybox</i>, to the default grey colour behind. I tried disabling foveated rendering and it seems to have solved both the weird "see-through
road" problem and the flickery rectangle problem. I'd like to be able to use foveated rendering for
the improved performance, but for now I'm going to be leaving it disabled.</p>
<p><h2>Timing</h2></p>
<p>I've added basic lap timing. I just defined an <a href="https://docs.godotengine.org/en/3.2/classes/class_area.html">Area</a> at the position of the start/finish line. Whenever the car enters the area,
the previous lap time is recorded and the current lap time is reset to 0.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2873"><img src="https://img.incoherency.co.uk/2873/thumb"></a><br></p>
<p>This does mean that you can take whatever route you want and it will still count as a valid lap, but that's fine for now. I'd probably want to add 2 or 3 split timing checkpoints around the track, which
need to be crossed in the correct order, and also an Area to define the track limits. If the car ever leaves the track limits Area then that lap time would be considered invalid for the
leaderboard, or something.</p>
<p>The Cadwell Park track model has several different layout options, named the "full", "MotoGP", and "Woodlands" layouts. We could quite easily put down a few cones, and adjust the split checkpoints and
track limits Area, to have several different "tracks" without needing any more 3D models, which might be handy.</p>
<p><h2>Menus</h2></p>
<p>I still need to work out how to do menus in VR. I assumed this would be easy and I would stumble across it by accident, but I haven't yet found anything obvious. The <a href="https://github.com/godotengine/godot-demo-projects/tree/master/viewport/gui_in_3d">gui_in_3d</a> demo project might be a good starting point.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2868"><img src="https://img.incoherency.co.uk/2868/thumb"></a><br></p>
<p><h2>Ghost car</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2874"><img src="https://img.incoherency.co.uk/2874/thumb"></a><br></p>
<p>The ghost car is textured in plain white, mainly because I found it too annoying to apply the proper textures, but also because ghosts are white. The ghost car is faded out when the player is
near it, by adjusting the alpha setting in
the "albedo" of the material. I considered trying to fade out the car using the "proximity fade" and "distance fade" settings on the <a href="https://docs.godotengine.org/en/3.2/classes/class_spatialmaterial.html?highlight=spatialmaterial">SpatialMaterial</a>, but found they did not really provide enough control.</p>
<p>I had quite a bit of trouble positioning the wheels. At first I put the wheel meshes as child nodes of the ghost car body, and then recorded the relative transform of the wheels on the real car (relative
to its body), and tried to replay these relative transforms onto the ghost car wheels, but it didn't work. They rotated around the wrong centre point, and around the wrong axis. I'm not sure why. Eventually
I settled on recording the global transforms of the wheels, and making the ghost wheels <i>not</i> child nodes of the ghost car. Then I just replay the global transforms and it all works correctly.</p>
<p>The ghost car sometimes looks quite bad because some of the back-faces are seen through the transparency. I'm not sure what is best to do about this. I tried enabling back-face culling, but it still looked
weird.</p>
<p>I think I would want the ghost car to be drawn completely opaque on to a separate buffer, and then composited into the scene with some transparency. Not really sure how to do this in Godot, but it would
solve the problem of seeing back-faces on the ghost car, without stopping you from seeing through it.</p>
<p><h2>Godot</h2></p>
<p>I'm really impressed with Godot. It saves <i>so</i> much time compared to writing everything from scratch, and the visual editor makes it easy to lay everything out in 3D space.</p>
<p>If I had my way, it would be easier to set object properties in GDScript. The way you set properties in Godot is with the properties editor, but this doesn't provide you with any way to write
comments next to the values, or compute the values from more human-friendly numbers, or from other constants. You can set the properties at startup time, but then the values won't be reflected in the
editor.</p>
<p>There are only about 500 lines of code in the entire game. It's a very productive way to make games.</p>
<p><h2>Steering wheel</h2></p>
<p>I have made a first attempt at a steering wheel for Oculus Quest controllers. Although this one doesn't work very well, I don't think it has <i>completely</i> disproven the concept. The controllers
are held onto the rotating part with magnets, so that the controllers can be easily removed from the steering wheel to operate the Oculus Quest menus.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2865"><img src="https://img.incoherency.co.uk/2865/thumb"></a><br></p>
<p>Problems include:</p>
<p><ul>
<li>Even though the magnets are quite strong, the controllers are slightly loose at the joint, which gives a very unconvincing feel. I'd want it to feel like the controllers are solidly connected together.</li>
<li>There's not enough room to clamp it to the desk without scraping your knuckles on the clamps (needs longer wooden bit).</li>
<li>The aluminium rod is not quite tight enough inside the central piece, which means it can rotate, which adds a second axis of "unconvincing feel".</li>
<li>And the worst bit: it becomes really hard to turn the wheel more than 90&deg; in either direction because your hands have to rotate. This means the steering sensitivity would need to be bumped up, but it's already more sensitive
than would be ideal, so I'm not sure what the solution is. Probably want to come up with a rising-rate curve so that you have fine control in the centre, and then rapid movement at the edges. I experimented
with a couple of different curves but didn't like anything I found.</li>
</ul></p>
<p><h2>Gameplay</h2></p>
<p>I think it would be cool to add an online leaderboard. Enforcing track limits is obviously a prerequisite to this. Once we have a leaderboard, it might be interesting to add
separate game modes. For example, there could be a 30-lap challenge, where instead of just trying to set a fast lap, you have to do 30 consecutive laps, which we could expect to
take about <i>30 * 105 seconds = 52.5 minutes</i>. That would enforce a more
conservative driving style because a crash would be undoing quite a lot of hard work. I'm not sure how track limits would work on the 30-lap challenge. Invalidating the entire session seems unfairly harsh.
Invalidating even an entire lap seems unfairly harsh. Maybe just a time penalty? But we'd have to make sure the time penalty is severe enough that you are always penalised for taking shortcuts. Maybe we
could say that if you leave the course during a lap, then the best time we'll allow you to score for that lap is 20 seconds worse than your worst legitimate lap? Not sure.</p>
<p>If we said that you could have N people start the 30-lap challenge simultaneously, and we'd render ghost cars of all your opponents onto your screen, then
we're actually not a million miles away from creating a collision body for each of the opponent cars and turning it into a full-contact online race! I'm probably
not going to implement this, but interesting to consider.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/oculus-quest-racing-progress.html</link>
   <guid>http://incoherency.co.uk/blog/stories/oculus-quest-racing-progress.html</guid>
   <pubDate>Wed, 19 Aug 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to import Assetto Corsa race tracks into Godot</title>
   <description><![CDATA[Assetto Corsa is a car racing game with emphasis on realism. It's basically
what I'm trying to do for the Oculus Quest, except it doesn't run on the Oculus Quest.
What it does have is a thriving community of freely-available cars and tracks on assettocorsa.club.
It is these free tracks that we'll be looking at importing into Godot.]]></description>
   <content:encoded><![CDATA[<p><a href="https://en.wikipedia.org/wiki/Assetto_Corsa">Assetto Corsa</a> is a car racing game with emphasis on realism. It's basically
what I'm <a href="https://incoherency.co.uk/blog/stories/oculus-quest-car-racing.html">trying to do for the Oculus Quest</a>, except it doesn't run on the Oculus Quest.
What it <i>does</i> have is a thriving community of freely-available cars and tracks on <a href="https://assettocorsa.club/">assettocorsa.club</a>.
It is these free tracks that we'll be looking at importing into Godot.</p>
<p>I started by importing <a href="https://assettocorsa.club/mods/tracks/cadwell-park.html">Cadwell Park</a> as it is quite small (good for the Oculus Quest)
but still interesting, and I've also done a trackday there in real life. You can <a href="https://www.youtube.com/watch?v=M1xzSrjKYhY">watch a video of me driving around Cadwell Park in the game</a> if you
want. I deleted half the trees, most of the vehicles, the crowd, etc. as I was really keen to keep the polygon count low. It still lags a bit in places but performance is basically acceptable.</p>
<p>What follows is a "guest post" by Quy Nguyen, who took the trouble to explain all this to me via email but does not have a website
to publish it on. I'd add to it:</p>
<p><ul>
<li>If you export from Blender in glTF format instead of FBX then you don't need to apply textures in Godot as it picks them up automatically.</li>
<li>Sometimes some triangles have normals inverted after importing into Godot. I still have not tracked down why, it is <i>possible</i> that it is related to the glTF export
from Blender.</li>
<li>Textures with transparency are opaque by default, you need to go into "Flags" for the material and enable "Transparent". I also found that
this caused depth issues (background objects drawn in front of foreground objects), but this went away when I went into "Parameters" and enabled "Alpha scissor". This
does mean you only get 1 bit of alpha channel, but that's better than having background objects drawn on top of stuff.</li>
<li>You don't need to duplicate the mesh and call it "...-colonly", you can just call one instance of the mesh "...-col" and Godot will use it as a collision mesh.</li>
<li>I have removed a hyperlink to a Windows binary of <tt>kn5conv.exe</tt> on mega.nz because I'm not completely sure of its provenance. I found the C# source for this program <a href="https://github.com/RaduMC/kn5-converter">on GitHub</a>
and wrote a Makefile to compile it on Linux, so I'd suggest using that: <a href="https://github.com/jes/kn5-converter">https://github.com/jes/kn5-converter</a>. If you're on Windows,
either compile the C# program the usual way, or go and find a dodgy binary and hope it's not malware.</li>
<li>The Assetto Corsa tracks that I looked at seem to use a shader to draw the grass, which means if you don't import the shader you just get aerial photography of the grass, which sucks. I probably
want to look at either porting the grass shader from Assetto Corsa or writing a new one.</li>
<li>I haven't yet worked out how to tell Godot VehicleBody to use a lower friction setting on the grass. It seems to ignore the surface friction and only use the friction of the tyre, which means the
car has just as much grip no matter what surface it drives on. But if you make sure to keep the asphalt and grass collision meshes separate, you can at least <i>assign</i> them a different friction
value.</li>
<li>The tracks I looked at had a second mesh with roughly the same geometry as the road surface, called the "groove", and textured with tyre marks. I'm not sure how this works in Assetto Corsa, but in
Godot it causes terrible <a href="https://en.wikipedia.org/wiki/Z-fighting">Z-fighting</a> as the 2 meshes occupy the same place. I just deleted the "groove" mesh, but it would be cool to be able
to have the tyre marks.</li>
</ul></p>
<p>Many thanks to Quy Nguyen for writing this!</p>
<p><hr></p>
<p><h2>How I Made Race Tracks In Godot<br><small>by Quy Nguyen</small></h2></p>
<p>I want to point out that all you need for this to work are Blender, Godot and a .kn5 file converter (I'll explain more)</p>
<p>The track was not me modelling it but actually a map from Assetto Corsa (mods) where it is imported to Blender where grouping objects into appropriate groups and making the collision shapes took place in. Then export from Blender to Godot and modify the textures in Godot just like how Bastiaan Olij did it in his first car game tutorial.</p>
<p>1. Getting the map from Assetto Corsa (mods)
Assetto Corsa is a great game with a nice community for mods from cars to tracks, so there are plenty of mods for this game out there. My favorite and seems safest place to get mods for the game is <a href="https://assettocorsa.club/mods/tracks/">https://assettocorsa.club/mods/tracks/</a>. So through the link there are plenty of tracks to choose from, I'll choose Top Gear Track for this. Here's a link if you wanted to use the same track: <a href="https://assettocorsa.club/mods/tracks/top-gear-test-track.html">https://assettocorsa.club/mods/tracks/top-gear-test-track.html</a></p>
<p><a class="img" href="https://img.incoherency.co.uk/2849"><img src="https://img.incoherency.co.uk/2849/thumb"></a></p>
<p>Click on a track and there should be a download button at the bottom of the screen</p>
<p>
This should link you to a Google Drive where you can download the .rar file. Open the file up and you should see the map in a .kn5 file.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2850"><img src="https://img.incoherency.co.uk/2850/thumb"></a></p>
<p>A .kn5 file is just an Assetto Corsa file so it won't work for any other application for it so it is required to have the .kn5 converter application that I mentioned on top. This application would convert it into a Wavefront (.obj) file where we'll import it through Blender later. To convert, simply copy the application and paste it in the same folder as the map</p>
<p><a class="img" href="https://img.incoherency.co.uk/2851"><img src="https://img.incoherency.co.uk/2851/thumb"></a></p>
<p>and drag the  .kn5 file drop on "kn5conv" like so</p>
<p><a class="img" href="https://img.incoherency.co.uk/2852"><img src="https://img.incoherency.co.uk/2852/thumb"></a></p>
<p>This should run the kn5 converter and it would look something like this</p>
<p><a class="img" href="https://img.incoherency.co.uk/2853"><img src="https://img.incoherency.co.uk/2853/thumb"></a></p>
<p>When it is done you should have a .obj file and a .fbx file of the map in the same folder where I would recommend to use the .obj file later on (I tried to use the fbx and Blender couldn't read it) and if you don't see the .obj file like below you might need to wait for the it. (You can tell if the converter is done or not by checking if it is still running at the background or not, when done it should close the program down it self)</p>
<p><a class="img" href="https://img.incoherency.co.uk/2854"><img src="https://img.incoherency.co.uk/2854/thumb"></a></p>
<p>2. Let's go to Blender</p>
<p>In Blender, create a new blend and delete everything (default cube, light, camera) then go to import > Wavefront(.obj) and direct to the folder that contains the map.</p>
<p>Notice to select the one WITHOUT the _ZMHack and if you did nothing will show up. Before importing the file, you'll need some adjustment for easier usage later on. The adjustment would be at the Geometry on the right side under Transform. Select "Split by Group" instead of the default "Split by Object" then import.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2855"><img src="https://img.incoherency.co.uk/2855/thumb"></a></p>
<p>At this point you should have the track which should look like this</p>
<p><a class="img" href="https://img.incoherency.co.uk/2856"><img src="https://img.incoherency.co.uk/2856/thumb"></a></p>
<p>Notice that the collection contains a lot of objects and this is one of the parts where it is a bit time consuming. You would have to manually go through each individual mesh and group them into specific groups. (Asphalt, Grass, .... these group depends on you to group them for later purpose in Godot of how you want these objects to interact in your game)</p>
<p><a class="img" href="https://img.incoherency.co.uk/2857"><img src="https://img.incoherency.co.uk/2857/thumb"></a></p>
<p>During grouping them, you might come across these</p>
<p><a class="img" href="https://img.incoherency.co.uk/2858"><img src="https://img.incoherency.co.uk/2858/thumb"></a></p>
<p>These have their purpose in Assetto Corsa for spawn points and timing checkpoints, but I would delete them here in Blender and later on use Godot's mesh to make them if lap time and different spawn points are needed.</p>
<p>Even though we have grouped them into groups, they are a big load of objects inside each group and we don't want Godot to take its time and process them one by one so it would make sense to make all the objects of a group to a single object. Here are pictures to show the process and what I really mean
a. Select all the objects in a group</p>
<p><a class="img" href="https://img.incoherency.co.uk/2859"><img src="https://img.incoherency.co.uk/2859/thumb"></a></p>
<p>b. Join them together</p>
<p><a class="img" href="https://img.incoherency.co.uk/2860"><img src="https://img.incoherency.co.uk/2860/thumb"></a></p>
<p>c. Now each group would have one object only and not crazy amounts where Godot could crash from it. However you can always purposely make them into several objects like cones, tires where you can hit them so each can have their own collision and would not all fall together but I am not doing it here. (You should be able to do it and if you need help I am here)</p>
<p><a class="img" href="https://img.incoherency.co.uk/2861"><img src="https://img.incoherency.co.uk/2861/thumb"></a></p>
<p>Now we are moving on to collision for Godot
Making complex collision shapes in Godot is pretty difficult and I would not be able to do it, so making Blender letting Godot to know what is collision and what is mesh can be shown down here.</p>
<p>First, you would need to duplicate the objects that you wanted to have collision shape for it (interactable objects)</p>
<p><a class="img" href="https://img.incoherency.co.uk/2862"><img src="https://img.incoherency.co.uk/2862/thumb"></a></p>
<p>Second, simply name the duplicated objects with an extension of "-colonly". Godot can recognize mesh with -colonly as collision shape</p>
<p><a class="img" href="https://img.incoherency.co.uk/2863"><img src="https://img.incoherency.co.uk/2863/thumb"></a></p>
<p>This should be the very end of the process in Blender, all left to do is export as an FBX file to Godot (we are doing FBX because it is guaranteed for Godot to recognize the collision shapes)</p>
<p><a class="img" href="https://img.incoherency.co.uk/2864"><img src="https://img.incoherency.co.uk/2864/thumb"></a></p>
<p>At this point I am sure you can finish the rest, a problem I am not sure how to avoid is how can you import an fbx file with materials on it? Applying everything manually all over again would make me sick 😂
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/assetto-corsa-race-tracks-in-godot.html</link>
   <guid>http://incoherency.co.uk/blog/stories/assetto-corsa-race-tracks-in-godot.html</guid>
   <pubDate>Thu, 13 Aug 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made a mechanical keyboard with 3d-printed switches</title>
   <description><![CDATA[The keyboard is done! This is basically the result of what I've been working on for the past 2 months, which has
involved 3 iterations of testing machines, over 100 printed switches, and now finally a keyboard that I can type on.
Unfortunately it is not a very good keyboard, but you can't win them all.]]></description>
   <content:encoded><![CDATA[<p>The keyboard is done! This is basically the result of what I've been working on for the past 2 months, which has
involved 3 iterations of testing machines, over 100 printed switches, and now finally a keyboard that I can type on.
Unfortunately it is not a very good keyboard, but you can't win them all.</p>
<p>Here's some pictures of the keyboard:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2843"><img src="https://img.incoherency.co.uk/2843/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/2844"><img src="https://img.incoherency.co.uk/2844/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/2845"><img src="https://img.incoherency.co.uk/2845/thumb"></a></p>
<p>And here's a video of me typing on it:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/iEBbCk1WJUk" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>(In the video it is a bit wobbly because the back is propped up to take the pressure off the exposed wiring. I have subsequently printed a couple of small legs to raise up
the back of the keyboard and now it is a lot <i>less</i> wobbly, but it could still do with some soft feet).</p>
<p>I am very happy with how the keyboard looks, and also happy that I have managed to produce a working keyboard using 3d-printed switches in the first place. I believe
this may be a world first.</p>
<p>That said, I started using the jesboard to write this blog post, and it was too annoying to type on so I went back to the Filco. Spending some time typing
on my homemade switches has given me a newfound appreciation for just how good Cherry MX switches are. I'm not sure what it is that makes the
jesboard so unpleasant to type on, there's just a general vagueness to it that makes typing frustrating. Pressing a single key up and down feels basically fine, which is why I hadn't
noticed this problem while developing the switches. But trying to use it as an actual keyboard, and type at a sensible speed, just feels <i>really</i> bad. It
is genuinely the worst keyboard I have ever used. So that's disappointing.</p>
<p>I think to improve upon this you'd probably want to reduce the activation force (that's easy, just make the spring thinner) and add some tactile feedback so it is easier to tell
when the switch has actually been pressed. Beyond that, I'm not sure.</p>
<p><h2>Switches</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2841"><img src="https://img.incoherency.co.uk/2841/thumb"></a></p>
<p>If you want to learn more about the switches, I would recommend looking at some of my other <a href="https://incoherency.co.uk/blog/tags/keyboard.html">posts tagged "keyboard"</a>, but in short:
pressing on the stem at the top compresses the spiral spring (I copied the spring design from <a href="https://www.youtube.com/channel/UCSsm4h2ccJMdR6bsAFyIu6A">Riskable 3D Printing</a>, he
is also developing 3d-printable keyboard switches, but using magnet sensors instead of making mechanical switches himself). Once
the stem is pressed down far enough, a contact wire bridges the 2 contacts at the bottom, activating the switch. As the switch is pressed further, the leaf spring compresses, allowing
the stem to move further down while allowing the contact wire to remain in place. Eventually the spiral spring bottoms out against its casing and then stem movement stops. When the key is released,
the spiral spring pushes everything back up to the top.</p>
<p>The leaf spring has a section in its bend that is narrow in the "other" axis, to allow it to easily tilt side-to-side to ensure good contact with both of the contact wires.</p>
<p>I don't have a good photo of the latest switch design, but I have this of an earlier version:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2757"><img src="https://img.incoherency.co.uk/2757/thumb"></a></p>
<p>The working principle is the same but the new version is a bit shorter.</p>
<p>The switches are printed in PETG. If you want to see them in action, you might enjoy my <a href="https://www.youtube.com/watch?v=hRBQBf6jzFM">video of operating the switch tester</a>.
The final incarnation of the switch design lasted over 350k presses in all cases, and some instances still hadn't failed at 500k presses. This is a lot lower than the "tens of millions" that might be
expected of a commercial switch, but it's a big improvement over <a href="https://incoherency.co.uk/blog/stories/keyswitch-failure.html">13907</a> which is where the first iteration failed, and that was on an extremely
gentle machine.</p>
<p>I said I was going to experiment with moving the activation point down to 75% of the plunger travel so as to reduce the strain on
the leaf spring. I did test this on the <a href="https://incoherency.co.uk/blog/stories/another-new-tester.html">new machine</a>, with 5 of the old design and 5 of the new design side-by-side, and the new design lasted almost
twice as long, so that was a good improvement.</p>
<p>The gold-plated "jewellery wire" that I bought off eBay ended up working well and soldering well (so I conclude it was not varnished),
and 4 metres (costing &pound;4) was <i>just</i> enough to do the entire keyboard.</p>
<p>If you want, you can <a href="https://incoherency.co.uk/interest/3dpswitch.tar.gz">download the switch CAD</a>, including STL and FreeCAD files.</p>
<p><h2>Case</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2805"><img src="https://img.incoherency.co.uk/2805/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/2804"><img src="https://img.incoherency.co.uk/2804/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/2832"><img src="https://img.incoherency.co.uk/2832/thumb"></a></p>
<p>The case is split into 2 halves that are then glued together, so that it fits on the bed of the 3D printer. There is a large rectangular hole at the top and bottom in each half, and a long bit of plastic
inside joining them, to add a bit more strength to the joint. There's not a lot to the case design really, it is just a shape to fit the switches into,
with a bulge at the top to house the microcontroller, an exit hole for the cable, stabiliser mounts, and a cool-looking logo. I made the general shape of the case halves in FreeCAD, and then imported the resulting STL
into OpenSCAD to cut out the holes for the switches, because I found it easier to get the layout correct with code.</p>
<p>I printed the logo in a different colour by having the printer stop and wait for me to change the filament at the layer height where the colour changes, using the
<a href="https://marlinfw.org/docs/gcode/M600.html">M600</a> G-code command. PrusaSlicer has a nice GUI for setting this up, so I didn't even need to manually edit the G-code.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2846"><img src="https://img.incoherency.co.uk/2846/thumb"></a></p>
<p>If I were to make another keyboard, I would give myself more space to work with underneath by reducing the thickness of the "solid" middle part that the switches are mounted in.
I found that there was not really enough room to run the diodes and wires. I would also add provision for a few screws to attach a bottom cover to protect the wiring inside.</p>
<p>The case and keycaps are printed in Prusament Galaxy Black PLA, which I think gives a really nice finish.</p>
<p><h2>Keycaps</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2848"><img src="https://img.incoherency.co.uk/2848/thumb"></a></p>
<p>The keycaps were designed using <a href="https://github.com/rsheldiii/KeyV2">KeyV2</a>, a free parametric keycap library for OpenSCAD. If you want to design
some keycaps, you should check out KeyV2. Its creator, <a href="https://github.com/rsheldiii">Bob</a>, is friendly and gave me helpful advice and assistance.</p>
<p>There are several different ways to make an ISO (UK-style) enter key in KeyV2, but I couldn't find any combination of settings that would let me have rounded corners, sloping top,
and dished top, so I ended up making the enter key by hand in FreeCAD.</p>
<p>I was originally going to use "outset" legends on the keycaps, like I used on the <a href="https://incoherency.co.uk/blog/stories/3pct-keyboard.html">macro keypad</a>. But I read this comment in the KeyV2 source
which changed my mind, so I used inset legends instead:</p>
<p><pre><code>// make legends outset instead of inset.
// broken off from artisan support since who wants outset legends?
$outset_legends = false;</code></pre></p>
<p>But having printed all the keycaps, I'm not sure whether I think inset legends actually <i>are</i> better. They range from "perfectly fine" to "almost invisible" depending on the lighting. I'd
say the outset legends were easier to read.</p>
<p><h2>Wiring</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2836"><img src="https://img.incoherency.co.uk/2836/thumb"></a></p>
<p>The switches are hand-wired in a 15x5 <a href="https://en.wikipedia.org/wiki/Keyboard_matrix_circuit">keyboard matrix</a>, with diodes allowing current to pass only in one direction. 14x5 would be enough
if you thought about it a bit more than I did, but 15x5 is fine.</p>
<p>Originally I was planning to use an Arduino for the microcontroller, which has only 16 IO pins. This would allow for an 8x8 matrix, but when I went to layout the wiring, I came up with this, where
red is columns and green is rows:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2824"><img src="https://img.incoherency.co.uk/2824/thumb"></a></p>
<p>Obviously this is too complicated to wire up in real life, particularly in the small amount of space provided in the bottom of my case. You may also notice it was too complicated for me to
lay out in GIMP, as I have failed to connect the full-stop and apostophe keys to any row. For these reasons I decided to use a <a href="https://www.pjrc.com/teensy/">Teensy</a> 2.0 instead, which allowed me to use a more sensible matrix layout:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2835"><img src="https://img.incoherency.co.uk/2835/thumb"></a></p>
<p>(I laid this out on <a href="https://kbfirmware.com/">kbfirmware.com</a>).</p>
<p>The other part of the wiring is that the USB cable has to reach the microcontroller. I left a 4mm hole in the side of the case for the cable to run through, but this is too small for the connector
on the end. I was originally planning to cut the connector off and solder the wires directly to the USB pads on the micocontroller board, but they were too small and annoying to access, so instead
I just soldered the MiniUSB end back on and plugged it in. It's a tight fit but it does the job.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2847"><img src="https://img.incoherency.co.uk/2847/thumb"></a></p>
<p>In hindsight, I am not sure whether I regret hand-wiring the keyboard. I toyed with the idea of getting a PCB made up that I could directly solder my switches to. It would certainly have
made it easier to put the keyboard together, but I thought outsourcing the manufacturing of a PCB kind of takes the edge off making your own switches...</p>
<p><h2>Stabilisers</h2></p>
<p>Here's a clip showing how the stabilisers work:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/ZTvDP3Qutwk" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>The idea is that when you press down on one side you cause the bar to rotate, which then pulls down on the other side of the switch, forcing the key to move down parallel (instead of rocking)
and activate the switch properly. The bar is made of 1.75mm stainless steel wire bent into a suitable shape. Thick stainless wire is quite hard to cut, but doable with a big-ish pair of nippers.</p>
<p>While trying to fit the stabilisers for the spacebar, I managed to break off the mounts attached to the case. This is bad news because the case halves are about a 10-hour print each, and aside from
that I had already soldered up all of the switches. To reprint the case halves would involve undoing all of my soldering work, and then 20 hours of printing, and then redoing all of the soldering.</p>
<p>I wasn't interested in redoing all of that work, so as a last resort I drilled a hole into the case in the position of each stabiliser mount, and printed 2 new stabiliser mounts, long enough to fit
in the holes. I printed the mounts in PETG so that they'd be less likely to break.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2842"><img src="https://img.incoherency.co.uk/2842/thumb"></a></p>
<p>This worked really well, disaster averted! The mounts were a tight fit in the drilled holes so I didn't even need to use any glue.</p>
<p><h2>QMK</h2></p>
<p>I used <a href="https://qmk.fm/">QMK</a> for the keyboard firmware, running on a Teensy 2.0. I found it quite hard to get started with my custom keyboard, because almost all of the documentation
is geared towards the case where you are using an off-the-shelf keyboard which is already defined in QMK. The key point I needed to know was that you can use the script "<tt>./util/new_keyboard.sh</tt>"
to create a new keyboard, and I found the <a href="https://beta.docs.qmk.fm/developing-qmk/c-development/hardware_avr">AVR Processors</a> page of the QMK documentation to be
most helpful. The process is something like:</p>
<p><ol>
<li>Clone the QMK repo: <pre><code>git clone https://github.com/qmk/qmk_firmware</code></pre></li>
<li>Install the QMK tool from PIP: <pre><code>sudo python3 -m pip install qmk</code></pre></li>
<li>Setup QMK: <pre><code>qmk setup</code></pre></li>
<li>Install the Teensy loader program: <pre><code>sudo apt install teensy-loader-cli</code></pre></li>
<li>Create a new keyboard: <pre><code>./util/new_keyboard.sh</code></pre></li>
<li>Edit <tt>./keyboards/your-keyboard-name/config.h</tt> to configure your matrix dimensions and IO pins</li>
<li>Edit <tt>./keyboards/your-keyboard-name/keymaps/default/keymap.c</tt> and configure your keymap. This is the hardest but most fun part. I looked at some keymaps of other 60% keyboards to
see how you're meant to do it.</li>
<li>Compile your firmware: <pre><code>qmk compile -kb your-keyboard-name -km default</code></pre></li>
<li>Flash the firwmare to the Teensy: <pre><code>teensy_loader_cli --mcu=TEENSY2 your-keyboard-name_default.hex -w</code></pre> The "-w" means it will wait until the Teensy is reset, so once you've entered that, hit the reset button on the Teensy and wait a few seconds, and you're done!</li>
</ol></p>
<p><h2>Conclusion</h2></p>
<p>Apart from the fact that the keyboard is quite unpleasant to type on, I'd say this project was mostly a success. I enjoyed the process of developing the switches, but although there is
obviously more work that could be done, I think I've had quite enough of it. I think my mistake was optimising for reliability instead of feel. If you want to work on 3d-printed switches, I
would suggest focusing primarily on the switch feel, and only optimise for reliability once you have switches that feel good to type on.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/jesboard.html</link>
   <guid>http://incoherency.co.uk/blog/stories/jesboard.html</guid>
   <pubDate>Fri, 07 Aug 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I'm working on a VR car racing game for Oculus Quest</title>
   <description><![CDATA[I've been playing a bit of Mini Motor
Racing X on the Oculus Quest recently. It's good. The experience of driving a car in virtual reality is
amazing, but this particular game is too much "game" and not enough "simulator" for my taste. I've always preferred
Gran Turismo to Mario Kart, for example. Unfortunately, the Quest is quite an unusual platform, and none of the
popular racing games are available for it. I recently discovered that the open source game engine
Godot has Oculus Quest support, so I'd like to make a basic car racing
simulator for Oculus Quest.]]></description>
   <content:encoded><![CDATA[<p>I've been playing a bit of <a href="https://www.oculus.com/experiences/quest/2371757336252737/">Mini Motor
Racing X</a> on the <a href="https://www.oculus.com/quest/">Oculus Quest</a> recently. It's good. The experience of driving a car in virtual reality is
amazing, but this particular game is too much "game" and not enough "simulator" for my taste. I've always preferred
Gran Turismo to Mario Kart, for example. Unfortunately, the Quest is quite an unusual platform, and none of the
popular racing games are available for it. I recently discovered that the open source game engine
<a href="https://godotengine.org/">Godot</a> has Oculus Quest support, so I'd like to make a basic car racing
simulator for Oculus Quest.</p>
<p>Here's a video of what I have at the moment, which is basically just <a href="https://github.com/BastiaanOlij">Bastiaan Olij</a>'s
<a href="https://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html">Godot Vehicle
Demo</a> but with Quest integration:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/35CSPjsevAY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>My issues with Mini Motor Racing X are that the tracks are too small, the cars are too slow, and the cars handle unreasonably well.
This means you can drive everywhere with the throttle wide open and you never have to brake, so apart from the "boost"
powerup that spawns at random, it just becomes a steering game. And the boost powerup means you don't get a fair attempt
at a lap record each time, because good boosts are critical for good lap times, and you might get boosts spawning in unlucky places.
If you want to see what Mini Motor Racing X looks like, I have <a href="https://www.youtube.com/watch?v=GtXgL2tOt8w">this video</a>.
I want to play something closer to Gran Turismo, but in VR.</p>
<p>Now, <i>obviously</i>, I can't make anything close to Gran Turismo. That would be too much work. But I can probably make something
that is a bit closer to Gran Turismo than Mini Motor Racing X is, so that's my goal.</p>
<p>My favourite way
of playing Gran Turismo was the "Time Trial" mode, where you're the only car on the track, and you're trying to set the
fastest lap time, racing against a "ghost" of your current best time. You don't have to worry about
AI cars being too fast or too slow, and you get a good clean lap with no traffic every lap. From an implementation perspective,
the Time Trial mode is good because the game doesn't have to draw more than 1 car, doesn't have to simulate more than 1 car, doesn't
need an AI driver implementation, and doesn't need to worry about collision detection between cars. This saves a lot of work. It's also
a good way to turn a single player game into a multiplayer game: just pass the controller around and give everyone N laps to
set their best time.</p>
<p>If you throw away everything that could possibly be thrown away, a car racing game becomes remarkably simple. All you're
left with is a circuit and a car. Then you just take control inputs from the user, simulate physics, and draw the results. How hard can it be?</p>
<p>I found it useful to post about the <a href="https://incoherency.co.uk/blog/tags/keyboard.html">keyboard project</a> while working on it, both because the act of putting thoughts
into words forces one to discover what they actually are, and
also because of the helpful feedback I got from other people who read about it, so I expect I will do the same with this project. Unlike the keyboard
project, a racing game doesn't have an obvious defined "finished" condition, which means it is liable to end up "unfinished". But I also
don't know if anyone other than me will ever want to play it, so maybe that's fine.</p>
<p>The Godot Vehicle Demo is an excellent
starting point for this project. So far all I have done is added Oculus Quest integration, made the track larger, and tried to muddle with the physics settings to
make it drive a bit more realistically. I haven't got very far, but I've got far enough to convince myself that I can make this work as long as I actually
try, and don't get bored of it.</p>
<p>Here is a list of things I want to do to turn the existing Godot Vehicle Demo into the racing game I want to play:</p>
<p><h2>Car physics</h2></p>
<p>Currently the car is simulated using Godot's <a href="https://docs.godotengine.org/en/stable/classes/class_vehiclebody.html">VehicleBody</a>,
which uses the "raycast vehicle" method from the <a href="https://pybullet.org/wordpress/">Bullet</a> physics engine. This represents the car
as a single <a href="https://en.wikipedia.org/wiki/Rigid_body">rigid body</a>, instead of having a separate body for each wheel. From the top of each wheel arch, a ray is cast directly down to find the
point that the wheel touches the ground. I looked at <a href="https://github.com/godotengine/godot/blob/master/thirdparty/bullet/BulletDynamics/Vehicle/btRaycastVehicle.cpp">the code</a>
but don't fully understand it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2809"><img src="https://img.incoherency.co.uk/2809/thumb"></a><br>
<small>(Screen capture from Ivan Novozhilov's <a href="https://www.youtube.com/watch?v=cG8tQxPYzKU">UE4 RayCast Vehicle Tutorial | Suspension</a> video).</small></p>
<p>The raycast vehicle doesn't actually have any wheels, which means all interactions between the wheels and the ground need to be faked.
Also the wheels fall through the ground, rather than pushing the chassis up, if the maximum suspension force is exceeded.
"Raycast vehicle" is a quick and dirty method that works well enough for a lot of cases, but I'm not sure I consider it satisfactory for my game. I don't see why
we can't create a rigid body for the car, a rigid body for each wheel, and add joint
constraints to join them together. Then I think the only "hack" we'd need is to manipulate the tyre friction based on <a href="http://www.racer.nl/reference/pacejka.htm">Pacejka's Magic Formula</a>,
and the rest of it would work for free. Maybe I just don't know enough about game physics to know why this wouldn't work? Failing that, we're probably left with adding more bodges on top of
the raycast vehicle.</p>
<p>Currently the tyre friction is set in some arbitrary units that I don't understand. The field is called "friction slip" rather than something like "coefficient of friction", so I'm not
even completely sure what it's trying to model. From the code it appears to be used as a simple coefficient of friction, but values around 1.0 (which would be quite a grippy tyre) result
in a very slippery driving experience. The <a href="https://docs.godotengine.org/en/stable/classes/class_vehiclewheel.html#class-vehiclewheel-property-wheel-friction-slip">documentation</a> suggests
using values between 0 and 1, but the default value is 10.5, so I don't get it.</p>
<p>The Godot Vehicle Demo does not include any model of air resistance. I had a first attempt at this by applying a braking force equal to what the air resistance should be, but
this is not realistic because braking forces are applied at the contact patch of the tyres, and air
resistance is applied at the centre of drag. Braking forces result in weight transfer towards the front wheels. With air resistance the weight transfer is reduced
or even reversed depending on where the centre of drag is relative to the centre of mass. I.e., if the centre of drag is above the centre of mass, then air resistance would transfer
weight onto the rear wheels instead.</p>
<p>Currently the engine has a fixed "force" value, which is then modulated by the throttle position. 100% throttle = 100% force. This is basically an engine that has a flat
torque curve all the way to infinite RPM. The only reason it can't reach infinite speed is because of the air resistance I applied to the brakes. I want to improve this by
modelling the engine RPM, and copying the torque curve from a real engine. I think the way to do this, in each timestep, is:</p>
<p><ul>
<li>compute current engine RPM as a function of the average of the rear wheels' RPM (this basically assumes an open diff, which is another variable we might want to control later on), by dividing by the current gear ratio</li>
<li>look up torque available at this RPM in torque curve</li>
<li>modulate available torque by throttle position</li>
<li>multiply this torque value by the gear ratio implied by the diff and selected gear</li>
<li>apply the resulting torque to the rear wheels</li>
</ul></p>
<p><a class="img" href="https://img.incoherency.co.uk/2810"><img src="https://img.incoherency.co.uk/2810/thumb"></a><br>
<small>(Internal combustion engine torque curve, from Car Throttle's <a href="https://www.carthrottle.com/post/how-do-electric-vehicles-produce-instant-torque/">article on electric vehicle torque</a>).</small></p>
<p>I'm not sure how you apply the resulting torque to the rear wheels through the diff. Maybe you just apply equal torque to both wheels? Maybe you split it according to the current difference in wheel
RPM? Both of these seem wrong. Need to try and find this out.</p>
<p>Also we probably want to say that if the computed engine RPM is too low (say, below 1000 RPM), then the clutch is disengaged and we just apply
a tickover RPM instead, otherwise the car would have basically no torque from a standstill.</p>
<p>The Godot Vehicle Demo initially had the car's centre of mass literally level with the ground. This is a good workaround for the raycast vehicle's tendency to roll over as soon
as it loses grip, but is not very realistic. As just one example, there is no weight transfer under braking, because the centre of mass lies in the same plane
as the braking forces. I raised the centre of mass to something I thought looked more believable but the car kept rolling over. I've now got it set about level with the very bottom of the floor
of the car, which is 10cm off the ground at full suspension compression.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2811"><img src="https://img.incoherency.co.uk/2811/thumb"></a></p>
<p>The car is extremely difficult to control, and I'm not quite sure why. The rear end is extremely twitchy, especially when there is a bump or a crest in the road and on corner entry.
You can see in the video that I am having quite a hard time keeping the car from spinning. I expect this twitchiness is a result of the raycast vehicle's fakery of basically
everything about the interaction between the wheels and the ground. Hopefully it goes away if I manage to create the rigid body model.</p>
<p>The car was initially quite twitchy even while driving in a straight line at modest speeds, but I solved this by adding 1&deg; of toe out to the front wheels.
That this helped is actually quite a good endorsement of the raycast vehicle model, because almost all real cars run with a slight toe-out, for the same reason: imagine driving along with both
front wheels pointing dead straight. If there is now any perturbation in the steering angle (for sake of argument: you steer 1&deg; left), then the car starts to turn left, which shifts weight onto
the right-hand front wheel. Since there is no toe-out, the right-hand front wheel is now pointing slightly left, so shifting weight onto it causes more turning: this is instability.
Now consider what would happen
if there was a slight toe-out: when the weight shifts on to the right-hand front wheel, it is now pointing either straight or slightly right, which counteracts the weight transfer and keeps the car
going in a straight line. (<b>Update 2020-08-18</b>: My Dad informs me that most road cars are actually set up with toe <i>in</i>, so this paragraph might just be totally bogus).</p>
<p>The car currently has no <a href="https://en.wikipedia.org/wiki/Ackermann_steering_geometry">Ackermann</a> on the steering geometry. This means the inside wheel and the outside wheel both steer by
the same angle, instead of the inside wheel turning tighter.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2812"><img src="https://img.incoherency.co.uk/2812/thumb"></a><br>
<small>(From <a href="https://en.wikipedia.org/wiki/Ackermann_steering_geometry">Wikipedia</a>).</small></p>
<p>The suspension currently moves each wheel in a perfect straight line up and down. In real life this is quite hard to achieve. I think front forks on a motorbike are the only
practical solution. Anything involving pivot points, wishbones, swinging arms, etc. will move in a curved path rather than a straight line.
But I think that I don't mind the "perfect" suspension model. It just makes the car easier to set up because you don't have to account for effects like
<a href="https://en.wikipedia.org/wiki/Bump_steer">bump steer</a>, or the camber angle changing as the suspension position changes.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2814"><img src="https://img.incoherency.co.uk/2814/thumb"></a><br>
<small>(From <a href="https://en.wikipedia.org/wiki/Double_wishbone_suspension">Wikipedia</a>).</small></p>
<p>Helpful resources for simulating car physics include <a href="http://autoxer.skiblack.com/phys_racing/contents.htm">Brian Beckman's Physics of Racing Series</a>, and <a href="https://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html">Marco Monster's Car Physics for Games</a>.</p>
<p><h2>Circuit</h2></p>
<p>The circuit is laid out within Godot by defining a <a href="https://en.wikipedia.org/wiki/B%C3%A9zier_curve">Bezier curve</a> and then sweeping a track cross section along it. This is a
really good way to quickly experiment with different track layouts, but it is slightly inflexible because it does not allow for variation of track width or texture, and it does not
allow us to produce cambered corners. The track is always perfectly parallel to the ground across the width of the road at all places. I probably want to make the track in <a href="https://www.blender.org/">Blender</a>,
based on a similar system of extruding a cross section through a path, but then manually touch up the result to make a more interesting circuit, and import the resulting graphics
mesh, and a simplified collision mesh, into Godot.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2816"><img src="https://img.incoherency.co.uk/2816/thumb"></a></p>
<p>Currently the grass is just as grippy as the tarmac. The grass should be a separate collision mesh with a separate friction value. For that matter, I don't actually know where the friction
of the road surface is configured. I couldn't find a setting for it anywhere, which might go some way to explaining why the "friction slip" values for the tyres have to be so high.</p>
<p>I want to make a better track layout. I don't yet know if I'm going to copy the layout of a real track using aerial photographs, or if I'm going to invent one. My favourite
track in Gran Turismo was Deep Forest, which is an invented one, so maybe that's the way to go. Maybe I could just copy my favourite sections from real-life roads and race tracks
and string them together into the ultimate race circuit.</p>
<p>The circuit could also do with having some kerbs, rumble strips, maybe gravel traps. Just some variation really to make it more interesting.</p>
<p><h2>Environment</h2></p>
<p>Currently the environment outside the circuit consists of some grass edges of the track, a grass-textured flat plane, and a <a href="https://en.wikipedia.org/wiki/Skybox_(video_games)">skybox</a>. This is a pretty barren world to go racing in. Originally the
track in the Vehicle Demo had some procedurally-generated barriers, but they used up too much GPU time so I took them out. I think I want to add some simpler barriers and decorate them
with textures instead of geometry.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2808"><img src="https://img.incoherency.co.uk/2808/thumb"></a></p>
<p>I want to add some objects at the sides of the track to use as braking markers as it is currently very difficult to reliably brake in the right place each lap because everywhere looks
exactly the same. This will probably be a combination of explicit distance markers on corner entry, and other random items of interest scattered about (maybe trees, bushes, rocks, bridges, little buildings?).</p>
<p>It would be cool to add some joke adverts on the walls or on billboards. If you come up with a fake company that you want included, send me the artwork
and I'll try and use it as long as it's not clearly bad or offensive in some way, and not a real company.</p>
<p>Currently the track's collision mesh has tall walls on it that prevent you from driving off the edge of the road. I am not a fan of invisible game walls. I think I'd prefer to let the car drive anywhere
where there isn't an actual wall, including falling off cliffs and such.</p>
<p><h2>Sound</h2></p>
<p>The game is currently totally silent. The single most important sound in any racing game is obviously the engine noise. Once I have the engine modelled for the purpose of the physics, I will be able to
use the calculated RPM to inform the engine noise. I think engine noise will want to be composed of a small number of separate noises mixed together, maybe something like:</p>
<p><ul>
<li>basic engine sound, increasing in frequency and amplitude with engine RPM</li>
<li>induction noise, increasing in frequency and amplitude with engine RPM, and in amplitude with throttle position</li>
<li>various exhaust note sounds, increasing in frequency with engine RPM, and in amplitude with how close the engine RPM is to the "resonant" frequency of that particular exhaust note</li>
<li>exhaust crackle, played whenever the throttle position is rapidly reduced at high RPM?</li>
</ul></p>
<p>We'd also want to add some road noise, which is played from the position of each wheel, with frequency and amplitude in proportion to wheel speed, and amplitude also modulated by the weight on that corner.  
Wind noise can be a simple whooshing sound that increases in amplitude with road speed.  
And whenever there is a large change in suspension load, we could make a bang or rattling noise come from that corner of the car.</p>
<p><h2>Input</h2></p>
<p>Currently the throttle comes from the right-hand trigger, brake comes from left-hand trigger, and steering angle comes from the angle between the left and right controller. In that sense, the controllers act
like a steering wheel. In Mini Motor Racing X you need to use the "grab" buttons to grab your controllers onto the in-game steering wheel, but once they're grabbed on you can wave them around wherever
you want and the steering angle still comes from the angle between the controllers.</p>
<p>Making the player hold down the grab button sucks, because your middle fingers get tired pointlessly: there is no scenario in a racing game where
I <i>don't</i> want to be holding the steering wheel, why make me do it explicitly? So we'll just say the player is always holding the wheel. Having the hands permanently
"attached to the wheel" also frees up the grab button for other purposes. I think I want
to use the middle fingers to do flappy-paddle-style gear changes.</p>
<p>One problem with using the VR controllers as a steering wheel is that they're not actually attached to each other, or to anything else. I have some vague plans to build a little desk-mounted steering wheel
that the controllers would attach to, so that way they rotate around a fixed centre and don't move relative to each other. This is a bit like the VR "gun stocks" you can get for 2-handed guns,
but for a steering wheel instead of a gun.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2820"><img src="https://img.incoherency.co.uk/2820/thumb"></a><br>
<small>(From drHEEB's <a href="https://www.thingiverse.com/thing:4220283">Oculus Quest and RiftS Gun Stock Magnetic Remix</a> on Thingiverse).</small></p>
<p>It would be cool to be able to use pedals instead of triggers for throttle and brake. I don't know how hard it is to connect a bluetooth game controller to the Oculus Quest, but if it is easy then it might be
worth looking at. I expect bluetooth racing pedals are a product you can just buy, but if not then I don't expect it would be a very complicated thing to make.</p>
<p><h2>Game stuff</h2></p>
<p>The reversing logic is a bit glitchy. If you squeeze the brake, the car slows to a stop. If you then release and reapply the brake, it starts reversing, as intended. If you then release the brake and
apply the throttle, it sometimes accelerates you backwards instead of forwards! I haven't looked very hard at the logic, because I expect the problem will disappear once I switch to the engine-and-gearbox
model with reverse as a selectable gear.</p>
<p>I currently have no way to write any text to the user. The Vehicle Demo project draws the car speed at top-left of the window, but this doesn't work in VR because there is no window. I tried adding a "Label" object positioned
50cm in front of the camera, but it didn't show up in VR. I don't know why. It would be helpful to be able to write text for debugging purposes.</p>
<p>The dashboard has several dials on it, but they currently do nothing. I think I probably want to ignore/remove the existing dials and make a "VR-optimised" dashboard for the car that indicates road speed,
RPM, and selected gear. Maybe with some of those fancy LEDs that indicate when you're approaching the redline.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2817"><img src="https://img.incoherency.co.uk/2817/thumb"></a></p>
<p>The shadows are <i>really</i> low resolution. I played with some of the shadow settings but couldn't work out what was causing it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2818"><img src="https://img.incoherency.co.uk/2818/thumb"></a><br>
<small>(This pic is from the Godot editor on my PC - the shadows are even worse inside the actual game).</small></p>
<p>Some of the textures inside the Godot editor have <a href="https://en.wikipedia.org/wiki/Normal_mapping">normal maps</a> which mean they appear physically textured instead of just flat images, but inside
the Quest the normal maps don't work. I expect this is a setting somewhere that improves performance on the Quest, but normal maps look great so I want to try and work out how to enable them, just to
see if they are going to be viable.</p>
<p>Even though I am keen to play the game in VR for the immersion, I want to be able to play it on the PC for testing purposes. It takes about 45 seconds to compile and upload the game to the Quest,
which makes for a frustrating edit-compile-test cycle.</p>
<p>The game doesn't yet have a way to time your laps. In principle this is as easy as counting the elapsed time between when you last crossed the finish line and when you next cross the finish line, but there
are some more subtleties to it, for example if you cross the finish line, turn around, and then cross it again in the opposite direction, that shouldn't count as a lap. Probably the answer is to add some invisible checkpoints around the lap that must be crossed in the correct sequence in order to count as a valid lap.</p>
<p>Once we can time laps, we should also record the car's position at each point during the lap so that it can be saved and replayed as a "ghost" car.</p>
<p>I don't currently have any way to provide menus inside the game. You're driving the car, and that's it. It would be handy to add some VR menu system so that you can change the setup of the car without
having to recompile the game, and it would also be useful in letting you save/load ghost times.</p>
<p>The road viewing angle is very low, which means you don't get a very good view of the track ahead, and the texture also looks awful. Not sure what to do about this. I expect adding barriers and scenery
would make it easier to see where the track goes, maybe that's enough.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2819"><img src="https://img.incoherency.co.uk/2819/thumb"></a><br></p>
<p>The game does not give a good sensation of speed. I expect this would be helped by improved scenery and also sound. I don't know if there's anything else we could do. Maybe make the driver's head bob
around a bit at speed? Or maybe in response to acceleration?</p>
<p>And obviously once everything works properly, the game would benefit from having more than 1 car and more than 1 track! For now I'm happy with just one. If you want to contribute cars or tracks, please
get in touch.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/oculus-quest-car-racing.html</link>
   <guid>http://incoherency.co.uk/blog/stories/oculus-quest-car-racing.html</guid>
   <pubDate>Sun, 26 Jul 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Another new switch tester, test results, and thoughts on the keyboard design</title>
   <description><![CDATA[Just an update on the keyboard switch project. I've built the new 10-way testing machine, ran a (somewhat inconclusive) test to work out the best
thickness for the leaf springs, and thought a bit on how I'm going to design the actual keyboard.]]></description>
   <content:encoded><![CDATA[<p>Just an update on the keyboard switch project. I've built the new 10-way testing machine, ran a (somewhat inconclusive) test to work out the best
thickness for the leaf springs, and thought a bit on how I'm going to design the actual keyboard.</p>
<p>Here's a video of operating the new testing machine, including usage of the CLI tool for controlling it:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/hRBQBf6jzFM" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p><small>I normally type faster than that but I was holding the camera with one hand.</small></p>
<p><h2>New tester</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2795"><img src="https://img.incoherency.co.uk/2795/thumb"></a></p>
<p>It is modelled after this one which I screenshotted from the Linus Tech Tips <a href="https://www.youtube.com/watch?v=9fNiJKh6q-E">tour of the Omron factory</a>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2712"><img src="https://img.incoherency.co.uk/2712/thumb"></a></p>
<p><h3>Mechanical</h2></p>
<p>Rather than use a <a href="https://en.wikipedia.org/wiki/Crank_%28mechanism%29">crank</a> to convert the motor rotation into linear motion, I thought I'd go for something a little more exotic.
I browsed through the <a href="http://507movements.com/">507 Mechanical Movements</a> website and settled on <a href="http://507movements.com/mm_090.html">number 90</a>. It uses a rotating cam to
slide a slotted "yoke" back and forth. Advantages over a crank are that it needs fewer bearings and takes up less space in the direction of travel. But mainly it is just more unusual.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2791"><img src="https://img.incoherency.co.uk/2791/thumb"></a></p>
<p><small>(Aside: I tried to copy the animated GIF from 507movements.com, but found that it is actually not a GIF, it is generated at runtime with JavaScript!)</small></p>
<p>The stepper motor, linear rods, and linear bearings are from my <a href="https://incoherency.co.uk/blog/stories/3d-printer.html">first 3d printer</a>. I can't remember where the roller bearing is from, I found it
in my tub of bearings. It doesn't appear to have been used much, so it either came out of something that was very clean, or it was a spare. It is marked "6002RS".</p>
<p>I managed to put together almost the entire machine for free, because I already had suitable parts and materials on hand. The only thing I had to buy was the stainless M4 nuts and bolts, which set
me back almost &pound4. It appears that I substantially overestimated how long I'd need them to be, but no problem.</p>
<p>I made the classic DIY mistake of putting everything too close together without regard for the fastener placement, so it's quite annoying to work on if I need to remove or modify any parts.</p>
<p><h3>Electronics</h2></p>
<p>To avoid the mess of jumper wires running everywhere like on the <a href="https://incoherency.co.uk/blog/stories/better-keyswitch-tester.html">previous tester</a>, I put the Arduino, stepper driver, and DC barrel jack
on a piece of stripboard:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2796"><img src="https://img.incoherency.co.uk/2796/thumb"></a></p>
<p>At the front, each switch needs to have a connection to an Arduino signal pin, ground, and +5v for the LED, and needs a resistor and LED. I wired these up on tiny bits of stripboard,
with 6x3 holes. I think this was superior to wiring it all up with loose wires, but still a bit messy. Fortunately it's all hidden and not very easy to see:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2797"><img src="https://img.incoherency.co.uk/2797/thumb"></a></p>
<p>The only reason this machine uses a stepper motor instead of a DC motor is because it is the most convenient motor I had lying around. I would have preferred to use a 12V DC motor
with integrated gearbox, but not badly enough to be worth paying for one (or, worse, waiting for it to arrive).</p>
<p>Obviously we want to run the stepper motor as fast as possible, but a problem with stepper motors is that they lose torque as they gain speed. At 900 rpm, I have occasional trouble with the stepper
motor stalling, and since I'm using an A4988 driver instead of a Trinamic one, I don't get any notification that the motor is stalled, and it just sits there buzzing until I manually intervene.
This can be solved by running it slower, but on balance I think I am still winning by running it fast and checking on it periodically: the time wasted not pressing switches while
stalled is made up for by the amount of extra presses while not stalled. I am already running it with the A4988 set to the highest current setting.</p>
<p>One great benefit of using a stepper motor is that we get precise positioning information for free. (Although, we'd also get this from a DC motor with an integrated rotary encoder, like
I used on the <a href="https://incoherency.co.uk/blog/stories/pikon-telescope-hardware.html">PiKon telescope mount</a>). Normally you need to "home" a stepper motor to work out where it is before
using it. For the switch tester I don't actually need a precise <i>absolute</i> position, I just need the offset to be the same each revolution, so my solution is to manually move the system to
roughly top-dead-centre before starting it running. You could index the position automatically any number of different ways, but manually homing it is good enough for me.</p>
<p><h3>Software</h3></p>
<p>The <a href="https://github.com/jes/keyswitch-tester/blob/master/bigmachine/bigmachine.ino">Arduino code</a> implements a serial CLI for controlling the machine. This just lets the PC turn
the motor on/off, and change the speed, and is used via a <a href="https://github.com/jes/keyswitch-tester/blob/master/bigmachine/monitor">monitor program</a> which lets the user start/stop
the motors, start/stop data logging, change the speed, and show graphs of the data with gnuplot, as shown in the video above.</p>
<p>I first tried to drive the stepper motor with <a href="https://www.airspayce.com/mikem/arduino/AccelStepper/">AccelStepper</a>, but it has the problem that you need to call it frequently enough
for it to toggle the step pin on and off, and this becomes a problem if the CPU is busy doing serial communication. If we miss a step, the motor stalls. No good.</p>
<p>I eventually implemented the stepper motor control by using the <a href="https://github.com/PaulStoffregen/TimerOne">TimerOne</a> library to trigger a timer interrupt, and then toggle the step pin
and increment the step count in the interrupt handler. To accelerate the motor, we just start the timer at a low frequency and increase it until we're at the target speed. I wondered if it would be possible
to use the AVR's hardware timers to both produce the square wave to toggle the step pin and keep count of how many steps have been done. It is easy to generate the square wave using Arduino's
<a href="https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/">tone()</a> function. <a href="https://www.grahamedgecombe.com/">Graham</a> said it would be possible to count
the number of steps by wiring the output of the step pin into an input pin and using the input pin as the clock source for a second timer configured to count up to 200 and then reset to 0, which would
be a cool way to do it, but not really necessary at the low-ish frequencies involved (6000 Hz for 900 rpm).</p>
<p><h2>Switch testing</h2></p>
<p><h3>Test</h3></p>
<p>I already knew that the weak part of the current switch design is the leaf spring, but I didn't
have good data on how long it can actually be expected to last, or whether a slightly
thinner or thicker spring would be better. I had guessed at 0.6 mm before, but for this test I printed
out 3 switches each for thicknesses of 0.5, 0.6, and 0.7 mm. I also threw in the "kaiche" Cherry MX
clone as a control.</p>
<p>The testing machine is very noisy. For this reason I ran it in the garage instead of the house, and
switched it off at night time. It sounds
almost exactly like a lawnmower engine running at a high tickover. I expect that for the last
couple of days I have been a small contributor to the <a href="https://www.bbc.co.uk/news/magazine-35344544">Bristol Hum</a>.</p>
<p>I was concerned that the PETG might wear out where the roller bearing rubs against it, but this does not seem
to have been a significant problem so far:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2798"><img src="https://img.incoherency.co.uk/2798/thumb"></a></p>
<p>You can see in some of the slow-motion video that the bearing mostly rolls against the plastic rather than rubbing, which is handy.</p>
<p><h3>Results</h3></p>
<p>It is quite hard to quantify what is a failed switch and what is not, because sometimes there is
a lot of contact bounce even in a perfectly good switch. For example, here's the chart from the
commercial "control" switch:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2786"><img src="https://img.incoherency.co.uk/2786/thumb"></a></p>
<p>The gap between 180,000 and 210,000 is where the motor had stalled but the software didn't know (for this reason I
subtracted 30,000 from the press count of every switch that exceeded 180,000). I expect it stalled because the broken leaf spring from
one of the failed switches got wedged and made it harder for the platform to move up and down. Don't know.</p>
<p>The "step" around 425,000 is where I stopped the motor overnight and then started it again
the next morning. There is a step because the 0 position at top-dead-centre was not quite identical.</p>
<p>But given that this switch still appears to work completely fine, we know that we can have at least
this much bounciness (red) and not consider it a problem. For this reason I mostly ignored
bounce information and classified a switch
as "failed" only after it had either clearly stopped working entirely, or its activation range had
become unpredictable or very small. Typically the switch gets bouncier over a long period but still
works fine, and then its activation range degrades over quite a short period, and then the leaf
spring breaks off and it either stops working entirely, or comes on and off unpredictably due
to the machine vibration, if the leaf spring fell off in a way that can still short the contacts.</p>
<p>This is what I estimated to be the useful lifetimes of the switches, grouped by leaf spring thickness:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2794"><img src="https://img.incoherency.co.uk/2794/thumb"></a></p>
<p>(The full charts of switch performance are available at the very bottom of this post).</p>
<p>So... I don't know what to make of this.</p>
<p>The (0.5, 400000) data point is from switch 0.
If you look at the range of switch activation positions in the graphs at the bottom of this post, then
you'll see that switch 0's was much smaller than the others for the entire test. This implies that the
wire was not making contact for as long, which means there is less stress on the leaf spring. That is
probably the reason that it lasted longer.</p>
<p>If we say switch 0 is an outlier and ignore it, then what remains
could look something more like a bell curve with a peak around 0.6 mm. So I'll probably stick
with 0.6 mm leaf springs.</p>
<p>If the reason that switch 0 lasted so much longer really <i>is</i> because its activation position
was in the wrong place (presumably I bent the leaf spring during assembly), then we might find that
the switches can be made to last longer if we deliberately move the activation position down,
which is a compromise I experimented with on the copper-tape-based contacts, but not to great
effect. I'm
not yet sure whether I will try this out with the leaf spring contacts, or whether I just say
"enough is enough" and move on to making the keyboard.</p>
<p><h2>Keyboard design thoughts</h2></p>
<p>I feel like this project is dragging on more than long enough, so I ought to try and get the keyboard finished before I lose
interest and stop working on it, which is my usual modus operandi. To that end, I intend to proceed with roughly the existing
switch design, even though it isn't good for quite as many presses as I'd prefer.</p>
<p><h3>Key height</h3></p>
<p>The only changes I definitely want to make to the switch design are to reduce the height. In order to produce a keyboard as slim
as my Filco (which is about typical for off-the-shelf mechanical keyboards), I'd need to lose 18 mm of height, compared to
my <a href="https://incoherency.co.uk/blog/stories/3pct-keyboard.html">macro keypad</a>. I have found 11 mm so far, as follows, which is probably
close enough to be tolerable.</p>
<p><ul>
<li><b>5 mm:</b> put the Arduino on its side at the back of the board, instead of flat underneath it</li>
<li><b>2 mm:</b> remove the rubber feet</li>
<li><b>1 mm:</b> reduce the gap between the keycap and switch body at bottom of stroke</li>
<li><b>1 mm:</b> reduce the height of the keycap</li>
<li><b>1 mm:</b> reduce the thickness of the bottom of the switch body</li>
<li><b>1 mm:</b> reduce the thickness of the attachment of the leaf spring to the plunger</li>
</ul></p>
<p>Only 2 mm of this actually requires any changes to the switch design, and they seem relatively harmless, so I expect
not to have any trouble, although I will do some testing to make sure it doesn't significantly affect
the switch lifespan.</p>
<p><h3>Copper wire</h3></p>
<p>"m0xte" on HN said that the copper contacts will oxidise "almost instantly". This hasn't been an issue so far, so I'm not sure
how "instantly" I should expect it. Nonetheless, I agree in principle, so I have purchased some gold-plated copper wire. It
is sold for jewellery-making, and I previously experimented with some of <a href="https://www.worryknot.co.uk/">Emma</a>'s
sterling silver jewellery-making wire and found that it didn't conduct very well, I think it had a very thin layer of varnish on it. If the gold-plated wire I have bought has varnish
on it then I probably won't bother trying to use it, but if it conducts easily then I will. It is 1 mm diameter gold-plated copper
wire bought on eBay, I have ordered 4 metres at a cost of &pound;1/metre which is probably not quite enough for the full keyboard, but enough to test with.</p>
<p><h3>Case halves</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/2793"><img src="https://img.incoherency.co.uk/2793/thumb"></a></p>
<p><a href="https://www.thingiverse.com/thing:3478494">SiCK-68</a> is a 3d-printable mechanical keyboard design using off-the-shelf
switches. It looks cool, and although I can't use it with my switches, it is still good inspiration
for case design.</p>
<p>This is how the SiCK-68 goes together:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2792"><img src="https://img.incoherency.co.uk/2792/thumb"></a></p>
<p>A full keyboard case will not fit on the bed of my printer in one go, which means it needs to be split into 2 halves. I was umming and ahhing about the best way to do this (I don't
want the halves to be too floppy, I want a good rigid connection). I think I'll do it basically like the SiCK-68: holes in each half, with dowel pins to join them. If I make sure to use
plenty of epoxy on the pins and along the split line, maybe it'll be strong enough. I'm probably not going to be hitting anything with the keyboard, so as long as it can stand up to
furious typing, I expect it'll be fine.</p>
<p><h3>Layout</h3></p>
<p>As far as I've been able to determine, there isn't actually a standard key spacing. Figures I could find ranged from 18.8 mm up to 19.3 mm.
I measured my Filco and found that they appear
to be placed at 19.1 mm intervals. I'll probably use a round 19.0.</p>
<p>I intend to use an Arduino Pro Micro for the microcontroller. The Pro Micro has 16 available IO pins, which means the largest <a href="https://en.wikipedia.org/wiki/Keyboard_matrix_circuit">keyboard
matrix</a> we can use is 8x8 or 64 keys. This precludes using the <a href="https://keyboardwhiz.com/tenkeyless/">Tenkeyless</a> layout which I use at the moment, or even the
<a href="http://keyboardcatalog.com/65-percent/tada68">TADA68</a> layout which the SiCK-68 uses, but does allow a 60% layout, like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2790"><img src="https://img.incoherency.co.uk/2790/thumb"></a></p>
<p>You could certainly pick a microcontroller with more pins. <a href="https://jamiedavies.me/">Jamie</a> recommended the Teensy 2.0, which
is available on eBay for &pound9 and judging by the pictures has either 27 or 29 (I'm not sure about 2 of them) available IO pins, which provides for up to 182 or
210 keys, which should be Enough For Anyone<sup>TM</sup>.
Another possibility would be to use 2 microcontrollers and have them communicate internally to create a larger keyboard.
It might even be funny to logically split the keyboard into 2 completely separate halves, each unaware of the other, and each controlled by a single Arduino. Linux
would think you were using two keyboards but that's probably not a problem.</p>
<p>I already have a bag full of Arduino Pro Micros so I'll use one of those instead of buying a Teensy. And, besides, the fewer switches I have to wire up, the better.</p>
<p>I don't know if I will actually get on with a 60% layout. I've never used one before. In practice I never use
the right Windows key, context menu key (???), or Ctrl key, so I'll probably use these as modifiers to
make it possible to type keys like Home/End/Delete, backticks, arrow keys, and so on. I expect there is already
some popular way to do this with QMK, I'll just need to research it a bit. There is actually both physical space
and 8x8-matrix space spare for 5 keys in place of the 4 large keys to the right of the space bar, without even
making the space bar shorter, so I could consider adding an extra modifier key there.</p>
<p>I'm basically
settled on using QMK for the firmware. Writing my own keyboard firmware sounds like fun, but it's also the same
kind of fun as designing my own switches, and I've probably had plenty of that kind of fun in this project already.</p>
<p><h3>Keycaps</h3></p>
<p>After I wrote <a href="https://incoherency.co.uk/blog/stories/3pct-keyboard.html">last time</a> about my troubles with the <a href="https://github.com/rsheldiii/KeyV2">KeyV2</a> parametric keycap library, its creator <a href="https://github.com/rsheldiii">Bob</a>
emailed me to explain how to use it! He even went as far as implementing a custom stem module which matches the design of my stems, so I am now definitely going to use
KeyV2. This is a massive win compared to modelling every individual key in FreeCAD.</p>
<p>KeyV2 also has support for putting the legends on the sides of the keys, which I want to do because it gives superior print quality on the lettering, compared to printing them on top,
and it looks cool.</p>
<p>That's all for now. The rest is just graphs from the switch test.</p>
<p><hr></p>
<p><h2>Test data</h2></p>
<p><h3>0. 0.5mm leaf spring</h3></p>
<p>400,000 presses.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2779"><img src="https://img.incoherency.co.uk/2779/thumb"></a></p>
<p><h3>1. 0.6mm leaf spring</h3></p>
<p>295,000 presses.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2780"><img src="https://img.incoherency.co.uk/2780/thumb"></a></p>
<p><h3>2. 0.7mm leaf spring</h3></p>
<p>280,000 presses.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2781"><img src="https://img.incoherency.co.uk/2781/thumb"></a></p>
<p><h3>3. 0.5mm leaf spring</h3></p>
<p>160,000 presses.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2782"><img src="https://img.incoherency.co.uk/2782/thumb"></a></p>
<p><h3>4. 0.6mm leaf spring</h3></p>
<p>170,000 presses.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2783"><img src="https://img.incoherency.co.uk/2783/thumb"></a></p>
<p><h3>5. 0.7mm leaf spring</h3></p>
<p>210,000 presses.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2784"><img src="https://img.incoherency.co.uk/2784/thumb"></a></p>
<p><h3>6. 0.5mm leaf spring</h3></p>
<p>110,000 presses.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2785"><img src="https://img.incoherency.co.uk/2785/thumb"></a></p>
<p><h3>7. "kaiche" commercial switch</h3></p>
<p>&gt;450,000 presses, still not broken.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2786"><img src="https://img.incoherency.co.uk/2786/thumb"></a></p>
<p><h3>8. 0.6mm leaf spring</h3></p>
<p>310,000 presses.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2787"><img src="https://img.incoherency.co.uk/2787/thumb"></a></p>
<p><h3>9. 0.7mm leaf spring</h3></p>
<p>220,000 presses.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2788"><img src="https://img.incoherency.co.uk/2788/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/another-new-tester.html</link>
   <guid>http://incoherency.co.uk/blog/stories/another-new-tester.html</guid>
   <pubDate>Wed, 15 Jul 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Secrets of the Hanayama Cast Marble</title>
   <description><![CDATA[Cast Marble is a mechanical puzzle sold by Hanayama.
It was invented by Bram Cohen (who you may recognise as the
inventor of BitTorrent) and Oskar
van Deventer, who has an interesting YouTube channel where he regularly posts
new puzzle designs.]]></description>
   <content:encoded><![CDATA[<p><a href="https://hanayama-toys.com/product/cast-marble/">Cast Marble</a> is a mechanical puzzle sold by <a href="https://hanayama-toys.com/">Hanayama</a>.
It was invented by <a href="https://en.wikipedia.org/wiki/Bram_Cohen">Bram Cohen</a> (who you may recognise as the
inventor of <a href="https://en.wikipedia.org/wiki/BitTorrent">BitTorrent</a>) and <a href="http://oskarvandeventer.nl/">Oskar
van Deventer</a>, who has an interesting <a href="https://www.youtube.com/user/OskarPuzzle">YouTube channel</a> where he regularly posts
new puzzle designs.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2765"><img src="https://img.incoherency.co.uk/2765/thumb"></a></p>
<p>The puzzle is made of 4 parts, which are 2 identical copies of 2 types of part. 2 of the parts form a ball in the centre, and the other 2 form a box around the outside.
The goal is to separate all of the parts.</p>
<p>(<b>Spoiler alert:</b> this post is intended to reveal the working principles of this puzzle to an even greater extent than you are likely to have
discovered by merely solving it. Don't read on if you still want to solve the puzzle yourself. Remember that "knowing the solution
cannot be reversed".)</p>
<p><h2>Solution</h2></p>
<p>The solution is quite simple, although very hard to discover. You need to align the cut line on the ball with the cut lines on
the outer box, and then twist the whole thing apart. After half a rotation, the parts have drifted apart sideways and can then
be separated easily.</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/Y-qPCfL1w2E" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>This seems a bit like half a turn on a screw thread, but unlike a screw thread it is
composed of 2 identical halves, rather than a male thread and a female thread. I initially thought that the centre of rotation of each part was inside the other part,
but actually they share a common centre of rotation, and it is a simple helix.</p>
<p><h2>Geometry</h2></p>
<p>This animation shows what we get by sweeping a rectangular profile through a helical path:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2772"><img src="https://img.incoherency.co.uk/2772/thumb"></a></p>
<p>If the centre line of the rectangular profile is collinear with the central axis, and the height of the rectangle
is half the pitch of the helix, then a length of the resulting shape takes up exactly half the volume of its bounding cylinder,
and 2 copies of it will thread together to form a solid cylinder without overlapping each other. This isn't just a trick of computer
graphics, it works in real life:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2769"><img src="https://img.incoherency.co.uk/2769/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2763"><img src="https://img.incoherency.co.uk/2763/thumb"></a></p>
<p>I don't know if this kind of shape has a name, I couldn't find one, but might not have known the right search
terms. I like to think of it as a "hermaphroditic screw thread".
It might be funny to make some real hermaphroditic screws, with proper screw heads, and use them to bolt stuff together.</p>
<p>This photograph shows how the puzzle parts share the hermaphroditic screw geometry:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2762"><img src="https://img.incoherency.co.uk/2762/thumb"></a></p>
<p>And we now see that the apparently complex surfaces of the puzzle parts are formed from just
a few primitive shapes!</p>
<p><h2>Reproduction</h2></p>
<p>I was surprised to find that the Hanayama Cast Marble uses a left-handed thread on its hermaphroditic screw. I'm not sure whether
this makes the puzzle easier to hold for a right-handed person, or harder to solve because people aren't used to
left-handed screw threads.</p>
<p>I measured the thread pitch by twisting the puzzle through half a turn and measuring the offset between the box parts, which was about 18 mm.
We then know that the thread pitch is twice this much, so the thread pitch is 36 mm.
It's a bit of a crude measurement but I think I got it right. It's close enough that the parts
fit together, anyway.</p>
<p>Once we understand this much, the design of the puzzle is mostly straightforward with <a href="https://en.wikipedia.org/wiki/Constructive_solid_geometry">CSG modelling</a>.</p>
<p>The ball parts are made by intersecting a sphere with the hermaphroditic screw.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2773"><img src="https://img.incoherency.co.uk/2773/thumb"></a></p>
<p>And the box parts are made by subtracting a sphere from a cuboid and then intersecting the result with the hermaphroditic screw.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2774"><img src="https://img.incoherency.co.uk/2774/thumb"></a></p>
<p>If you want to print your own copy, you can <a href="https://incoherency.co.uk/interest/cast-marble.tar.gz">download the STL files</a>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2764"><img src="https://img.incoherency.co.uk/2764/thumb"></a></p>
<p>The parts created this way are mostly interchangeable with the original puzzle parts:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2766"><img src="https://img.incoherency.co.uk/2766/thumb"></a></p>
<p>Although the printed box is not quite symmetrical, because I obviously cut it from the wrong place
in the thread:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2767"><img src="https://img.incoherency.co.uk/2767/thumb"></a></p>
<p><h2>Rounded edge</h2></p>
<p>Having put the printed puzzle together, I discovered one extra trick up the Cast Marble's sleeve!</p>
<p>Part of the reason the Cast Marble is so difficult to solve is because the box parts can rotate
around the centre in a way that is not used in the solution:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2775"><img src="https://img.incoherency.co.uk/2775/thumb"></a></p>
<p>This is due to a rounded edge on the box parts, which does not naturally occur from the
basic shape of the puzzle:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2776"><img src="https://img.incoherency.co.uk/2776/thumb"></a></p>
<p><h2>More</h2></p>
<p>An interesting property of the hermaphroditic thread is that any 2 threads will fit together, provided they have the same pitch and profile,
<i>regardless of their diameter</i>!</p>
<p>This means we could use the hermaphroditic thread to cut anything into 2 parts in a way that allows them
to thread together. I tried to do this with a few models I found on Thingiverse but they had
quite a lot of triangles, and FreeCAD
exhausted my machine's available RAM and crashed before it completed the intersection. In principle it would work though.</p>
<p>In addition to extending up/down to infinity, we can also extend our helix
outwards (radially) to infinity. This leads to 2 identical half-universes that can be screwed together, which is
quite a bizarre concept to wrap your head around. It's surprising that it's even possible. I would be interested to
learn of any other ways of splitting an infinite space into 2 identical halves that can move but
also constrain each other, because they might lead to low-hanging fruit
for new puzzle designs.</p>
<p>It might be interesting to experiment with alternative thread profiles. You need the inner edge to be a straight line segment
collinear with the central axis, but there's no reason that the upper and lower edges of the profile need to be
straight. They can be whatever you want as long as they match:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2777"><img src="https://img.incoherency.co.uk/2777/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/hanayama-cast-marble.html</link>
   <guid>http://incoherency.co.uk/blog/stories/hanayama-cast-marble.html</guid>
   <pubDate>Wed, 08 Jul 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made a macro keypad with 3d-printed switches</title>
   <description><![CDATA[Latest on the 3d-printed keyboard switch project: I've reached a switch design that I think is probably reliable enough,
and I've put 3 of them together to form a macro keypad just to see how it all goes together before I commit to a
full keyboard. I don't have a number for how many presses the switch lasts, other than to say that
the motor on the testing machine stopped working before the switch did (after about 250,000 presses).]]></description>
   <content:encoded><![CDATA[<p>Latest on the 3d-printed keyboard switch project: I've reached a switch design that I think is probably reliable enough,
and I've put 3 of them together to form a macro keypad just to see how it all goes together before I commit to a
full keyboard. I don't have a number for how many presses the switch lasts, other than to say that
the motor on the testing machine stopped working before the switch did (after about 250,000 presses).</p>
<p><a class="img" href="https://img.incoherency.co.uk/2745"><img src="https://img.incoherency.co.uk/2745/thumb"></a></p>
<p>You can <a href="https://www.youtube.com/watch?v=uHkOPBxnLtM">watch my short demo video</a> if you want.</p>
<p>"80%" and "60%" keyboard layouts are quite popular, which are correspondingly reduced versions of a full keyboard layout.
I like to think of this keypad as a "3%" keyboard, it's fine as long as you only want to type "jes".</p>
<p><a class="img" href="https://img.incoherency.co.uk/2746"><img src="https://img.incoherency.co.uk/2746/thumb"></a></p>
<p>It's controlled by an Arduino Pro Micro. It's hard to tell from the pic because of the hot glue, but the switches are wired up to pins 2, 3, and 4, from
the other side of the board.</p>
<p>For the software side of it, I used the <a href="https://www.arduino.cc/reference/en/language/functions/usb/keyboard/">Arduino Keyboard library</a>,
using <a href="https://gist.github.com/jes/fe1aeb18457a06562516372684d1bd47">this quick and dirty Arduino code</a>.
Approximately all of the code is just related to the debounce logic.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2748"><img src="https://img.incoherency.co.uk/2748/thumb"></a></p>
<p>The switches are printed in some generic no-name clear PETG.
The case and keycaps are printed in <a href="https://shop.prusa3d.com/en/prusament/711-prusament-pla-prusa-galaxy-black-1kg.html">Prusament Galaxy Black PLA</a>.
I'm a big fan of this filament. The glittery effect means the layer lines almost completely disappear. It's basically the same effect you get when printing with
carbon fibre-filled nylon, but with none of the difficulties of printing carbon fibre-filled nylon.</p>
<p>All of these parts, including the switches, were printed on my new <a href="https://www.prusa3d.com/original-prusa-mini/">Prusa Mini</a> printer, which arrived last week and I'm very pleased
with so far.</p>
<p><h2>Switches</h2></p>
<p>The problem with the switch design <a href="https://incoherency.co.uk/blog/stories/keyswitch-update.html">from last time</a> was that the copper tape was splitting apart, which prevents it from conducting along
its full length. I initially thought I had
solved this by applying a 2nd layer of copper tape, but that turned out not to be a workable solution. I did a bunch of tests of various combinations of 50% and 75% activation position, and 1 or 2 layers of copper
tape, and found no significant correlation between either of those 2 variables and how long the switch lasts. The switches lasted between 225 presses and 330,000 presses before
failure. 7 failed by the copper tape splitting, 2 failed by the PETG spiral spring breaking (both after more than 200,000 presses), and 1 didn't seem to have any broken parts, it just wasn't reliably working any more.</p>
<p>This is the CAD model of the latest design:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2749"><img src="https://img.incoherency.co.uk/2749/thumb"></a></p>
<p>The "leaf spring" has that funny shape in its bend so that it can tilt easily, which ensures that it makes reliable contact with <i>both</i> contact wires, instead of
just the first one it happens to touch.</p>
<p>And here's a slow-motion video showing how it works (a slightly earlier iteration, but the same concept):</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/peXFqVMugO4" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>Also, just for fun, I did some <a href="https://incoherency.co.uk/blog/stories/freecad-fea.html">FEA</a> on the spiral spring
design, and it behaved just like the real version:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2724"><img src="https://img.incoherency.co.uk/2724/thumb"></a></p>
<p>The red areas show the areas of highest stress, and indeed the springs tend to break around
the middle of the spiral.</p>
<p><h2>Print your own</h2></p>
<p>I consider this a "release candidate" rather than a finished design, because there is still
some work to do on it (in particular, I want to make it a bit less tall). But you can have it if you want it.</p>
<p>You will need:</p>
<p><ul>
<li>FDM 3D printer (although I'd also be interested to see results from resin printers!)</li>
<li>PETG filament. You can try other materials. PLA works but makes for a heavier feel and breaks more quickly.</li>
<li>1.0 mm diameter copper wire, 90 mm length per switch should be more than enough</li>
</ul></p>
<p><a href="https://incoherency.co.uk/interest/3dpswitch-rc1.tar.gz">Download the STL files</a> and arrange them on the build plate something like this (you'll probably have to rotate the spiral spring):</p>
<p><a class="img" href="https://img.incoherency.co.uk/2750"><img src="https://img.incoherency.co.uk/2750/thumb"></a></p>
<p>I suggest printing more than 1 of the "leafspring" part as it is a small part quite likely to
have defects in the print. Make sure you're printing at
a fine enough quality level to include all the features. In particular, make sure (both) the spirals on
the spring are connected all the way around, and that the leaf spring is connected all the way
along. I use the "0.15mm QUALITY" setting in PrusaSlicer. You shouldn't need any support material.
You might need to enable "detect thin walls".</p>
<p>You might need to add up to -0.3mm of X/Y size compensation. I have found that when printing
this on the Prusa Mini, optimal clearance is achieved when the 3.0 mm plunger rides inside
a 3.0 mm hole. On previous printers I've owned, this wouldn't even fit together. I'm not sure
what's going on, but obviously I modelled it to print on my machine, so you might need to apply X/Y
compensation on yours.</p>
<p><b>Step 1:</b> Print the parts. It takes about 40 minutes for me.</p>
<p><b>Step 2:</b> Clean up any stringing inside the case from the PETG. I use a lighter to burn off the worst of it,
and then a Stanley knife to trim off what remains.</p>
<p><b>Step 3:</b> Examine the spiral spring and ensure that it moves freely. You might need to cut any
stringing between the spirals with a knife, or re-print with different X/Y compensation, depending on whether it is a few small
tight spots or bad clearance all the way along.</p>
<p><b>Step 4:</b> Slide the spiral spring into the shelf at the top of the case. The orientation is not
critical, I tend to slide it in with the smoothest sides against the case just to make life easy
for myself.</p>
<p><b>Step 5:</b> Push the plunger through the top hole in the case, through the hole in the spiral
spring, and through the middle hole in the case. Verify that it moves up and down freely and that
the spring reliably returns it to the top. If not, take it back out and trim the tight spots with
a knife.</p>
<p><b>Step 6:</b> Cut off about a 13mm length of the copper wire. Slide it into the hole in the
leaf spring. If you can't get it through, you might need to widen the hole with a pin or sharp tool of
some kind. Use whatever you have.</p>
<p><b>Step 7:</b> Press the plunger down slightly to expose the attachment end inside the lower
chamber of the switch. Using a small pair of pliers or tweezers, push the attachment part of the
leaf spring onto the end of the plunger. Make sure it is pushed home. Looking in the big hole
at the bottom of the case, you should see the leaf spring roughly centred. When you let go
of the plunger, the spiral spring should still be stretched out slightly. This is desired, without
this preload the switch would start moving at 0 force.</p>
<p><b>Step 8:</b> Cut off 2x roughly 35mm lengths of copper wire. Using a pair of pliers, put a bend about
5mm from
one end. Insert the non-bent end through 1 of the wire holes and out the other side. Bend the wire
down the other side, and then in whatever direction you want your contacts to point. Repeat for
the second wire.</p>
<p>You should now have something that looks a bit like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2752"><img src="https://img.incoherency.co.uk/2752/thumb"></a></p>
<p>And that should be it! Manually press the switch a few times and visually verify that the middle
copper wire appears to be making good contact with the other 2 wires, and then you're ready to
assemble it into a circuit! If you want it mechanically attached to a PCB, you could leave a longer
length of wire coming out of the first side, and you'd then have 4 soldering points. Otherwise,
mount it inside a 14mm square hole. You'll probably need cut-outs in the corners to accommodate
the wires sticking out, like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2753"><img src="https://img.incoherency.co.uk/2753/thumb"></a></p>
<p>If you make one (or more!) I'd be really interested to hear your opinion on what could be designed
better, and to see pictures of your results. Email me: <a href="mailto:james@incoherency.co.uk">james@incoherency.co.uk</a>.</p>
<p><h2>Next steps</h2></p>
<p>We're getting pretty close to being able to put together a finished keyboard. I still
have the following things to do:</p>
<p><h3>Testing</h3></p>
<p>It would be good to get an accurate value for the number of presses that the switches can take. I
think currently a lot of the variability comes from the height at which the switch is positioned
relative to the tester. If it's doing 0.1mm short of a full stroke, the switch is likely to last
significantly longer than if it is being hammered 0.1mm longer than a full stroke. This is hard to
configure as I have only very coarse control of the height.</p>
<p>I watched the Linus Tech Tips tours of <a href="https://www.youtube.com/watch?v=Pu1gP4PfqCQ">the
Cherry MX factory</a> and <a href="https://www.youtube.com/watch?v=9fNiJKh6q-E">the Omron factory</a>. They're both interesting and worth watching. I took a screenshot of this testing machine in the
Omron video:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2712"><img src="https://img.incoherency.co.uk/2712/thumb"></a></p>
<p>So there we have a single motor raising a platform up and down which is pressing 10 switches
at once. The platform glides on a pair of linear rails, and the exact vertical position of the press
is finely adjusted with a separate screw for each switch. The moving platform also has
a spring at each end, I am not completely sure why, I think just to take up some of its weight, to
reduce the load on the motor.</p>
<p>But this is a much better way to gang-test switches than what I have at the moment, which involves
wiring up a separate motor for each switch and gets messy quickly:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2755"><img src="https://img.incoherency.co.uk/2755/thumb"></a></p>
<p>I'm past the point where more testing is critical (famous last words, I know), but it would be good
to do anyway, so I'd like to make a small-scale copy of the Omron testing machine.</p>
<p><h3>Switches</h3></p>
<p>The switch fits in a 14mm square hole (apart from the protruding wires), which is the same size
as a Cherry MX switch, but the total height from the bottom of the switch to the top of the keycap
is almost twice as large, about 45 mm vs 25 mm:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2757"><img src="https://img.incoherency.co.uk/2757/thumb"></a></p>
<p>This directly translates to increased keyboard height, so it would be good to cut this down
as much as possible. I should be able to lose 2 mm from the wire support at the bottom of the switch,
and another 1 or 2 mm in the height of the leaf spring attachment, but there's no way it's going to be
as thin as the Cherry MX.</p>
<p>I'd like to find a way to add a tactile bump (ideally with a clicky noise) to the motion of
the plunger. I did try simply adding a bump to the side of the casing that would catch on the
leaf spring, but it didn't work very reliably.</p>
<p><h3>Keycaps</h3></p>
<p>Currently my keycaps are based on the one I designed in <a href="https://incoherency.co.uk/blog/cad-dojo/stories/keycap.html">my
CAD Dojo project</a>. This is suboptimal for several reasons:</p>
<p><ol>
<li>adding text in FreeCAD is extremely time-consuming, and it can't be edited without deleting it and re-creating it (i.e.
there would be a substantial O(n) effort to make keycaps for an entire keyboard)</li>
<li>the keycaps should have a slightly different profile on each row</li>
<li>there should be some keycaps that are different shapes and sizes (tab, caps lock, shift, enter, space, backspace, etc.)</li>
</ol></p>
<p>This picture of my Filco Majestouch 2 Tenkeyless shows the different keycap profiles on each row:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2650"><img src="https://img.incoherency.co.uk/2650/thumb"></a></p>
<p>I probably want to write some OpenSCAD code to generate the keycaps instead of using FreeCAD.</p>
<p>I found a project <a href="https://github.com/rsheldiii/KeyV2">KeyV2</a> that is a parametric
keycap library, although I found it quite hard to work out how to add support for custom
switches. I haven't yet worked out whether it would be easier to make KeyV2 do what I want or
whether I should start from scratch.</p>
<p>I also probably need to add some sort of stabiliser, at least to the space bar and probably
to the enter key, backspace key, and right shift key as well. A stabiliser is a mechanism
underneath the keycap that keeps the keycap moving up and down vertically, instead of rocking over
the switch, in the event that it is pressed on one side instead of in the middle. It typically
works exactly the same way as an <a href="https://en.wikipedia.org/wiki/Anti-roll_bar">anti-roll bar</a> on car suspension: when one side moves down, the bar rotates from that end. The rotation is
transmitted to the other end of the bar, which also rotates, and pulls the other side down.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2758"><img src="https://img.incoherency.co.uk/2758/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2759"><img src="https://img.incoherency.co.uk/2759/thumb"></a></p>
<p>(Keyboard image from <a href="https://support.wasdkeyboards.com/hc/en-us/community/posts/360027414954-V3-Stabilizers-are-horrible">WASD Keyboard support forum</a>; Car suspension image from <a href="https://en.wikipedia.org/wiki/Anti-roll_bar">Wikipedia</a>)</p>
<p>Finally, I might consider reducing the layer height at the top surface of the keycaps, to
reduce the "contour lines" effect:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2760"><img src="https://img.incoherency.co.uk/2760/thumb"></a></p>
<p><h3>Keyboard</h2></p>
<p>Even without reducing the height of the switches, I could reduce the height of the keyboard
by sticking the Arduino vertically, behind the switches, instead of horizontally, underneath
them. That would allow the switch bodies to sit much closer to the bottom. It's probably worth doing.</p>
<p>I probably want to either remove or paint over the LEDs on the Arduino, because currently I get
a funny red and green glow coming from the bottom of the keypad, which I don't want to happen
on the real keyboard.</p>
<p>And I could consider running <a href="https://qmk.fm/">QMK</a>, instead of writing my own
control software. This would get me lots of fancy features for free, so as long as it is easy
enough to get it to work with my switches, it's probably the way to go.</p>
<p>That's all for now. If you're following along with  the keyboard switch project, please get in touch.
I'd love to hear feedback on anything you have thoughts on.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/3pct-keyboard.html</link>
   <guid>http://incoherency.co.uk/blog/stories/3pct-keyboard.html</guid>
   <pubDate>Mon, 06 Jul 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Making a game with 24a2</title>
   <description><![CDATA[24a2 is an "ultra-minimalist" game engine. It was posted
on Hacker News this morning and I found it so interesting that I decided to take a day off from
breaking keyboard switches and make a tiny game
instead.]]></description>
   <content:encoded><![CDATA[<p><a href="https://24a2.routley.io/">24a2</a> is an "ultra-minimalist" game engine. It was posted
on Hacker News this morning and I found it so interesting that I decided to take a day off from
<a href="https://incoherency.co.uk/blog/stories/keyswitch-update.html">breaking keyboard switches</a> and make a tiny game
instead.</p>
<p>Playing with a new game engine was a perfect Sunday project for me at the moment, because I'm
currently reading & enjoying <a href="https://en.wikipedia.org/wiki/Masters_of_Doom">Masters
of Doom</a> about <a href="https://en.wikipedia.org/wiki/Id_Software">id Software</a>, John
Carmack, and John Romero.
I would also definitely recommend John Carmack's <a href="https://www.youtube.com/watch?v=udlMSe5-zP8">appearance on the Joe Rogan Experience</a>.</p>
<p>I thoroughly enjoyed using 24a2, it brought back all the fun
that got me into programming in the first place.</p>
<p>Paradoxically, the reason it is so easy to make a game with 24a2 is that it so severely constrains you.
The only keyboard input available is arrow key presses. The only display output is a 24x24 grid
of dots, and there are only 9 colours. There's no audio at all.</p>
<p>The game I made is called "24invaders" and it is a <a href="https://en.wikipedia.org/wiki/Space_Invaders">Space Invaders</a>
clone.</p>
<p><ul>
<li><a href="https://incoherency.co.uk/24invaders">Play 24invaders now &raquo;</a></li>
</ul></p>
<p><a href="https://incoherency.co.uk/24invaders"><img src="https://img.incoherency.co.uk/2713"></a></p>
<p>The <a href="https://24a2.routley.io/tutorial/">24a2 tutorial</a> takes you through setting up a basic game where
the player can move around the screen and score a point every time he steps on a green dot. But if you've ever
written a game or any kind of physics simulation before, then you can safely skip the tutorial and refer
directly to the <a href="https://24a2.routley.io/reference/">reference manual</a>. It is extremely short.</p>
<p>Typically, when making a game, you will want to decouple your logic from your rendering, so that if the
graphics start to lag they don't slow down the logic. In 24a2 you don't waste your time even thinking
about such problems. You only have 576 pixels to draw anyway so it probably won't be a problem.</p>
<p><h2>The player</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2716"><img src="https://img.incoherency.co.uk/2716/thumb"></a></p>
<p>I started by making the game draw the player on the screen and allow the user to move it left and
right with the arrow keys. 24a2 only tells you about key <i>press</i> events. This means you don't
get to find out whether the key was just tapped or whether it is being held down. That means that
if you want to move the player a long way, you have to tap the arrow key a lot of times. I
considered hacking 24a2 to tell me the key state, but realised it is silly to use an engine
that deliberately constrains you and then remove the constraints.</p>
<p>I wanted the game to stand out a bit compared to the 24a2 examples, so rather than use a single dot for
the player, I made it look a bit like a spaceship with a gun on the front.</p>
<p>OK, it doesn't look very much like a spaceship with a gun, but what can you do? The tiny display
means you don't have much scope to draw fancy graphics, and that is a good thing because "programmer
art" is notoriously bad, but this way nobody minds.</p>
<p>Rather than make my drawing code manually plot each pixel, I defined the picture of the player
in ASCII, and then wrote a function to draw the "sprite".</p>
<p><pre><code>let playerSprite = makeSprite([
    " # ",
    "###",
]);</code></pre></p>
<p>(The "<tt>makeSprite()</tt>" call is because I was planning to use <tt>eval</tt> to compile the sprite into a
function that would draw it, but that's a pointless premature optimisation, especially at 24x24, so I
never bothered to actually implement that. So "<tt>makeSprite()</tt>" just returns its input and "<tt>drawSprite()</tt>"
does everything.)</p>
<p><h2>The player's bullet</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2717"><img src="https://img.incoherency.co.uk/2717/thumb"></a></p>
<p>Something that always annoyed me about Space Invaders is that once you've fired the gun, you can't fire again
until your bullet either hits something or leaves the screen. This means that if you miss, you have a long wait
before you can take another shot. I've always somewhat suspected that this was really only done so that the
game does not need to keep track of more than 1 player bullet.</p>
<p>But it's a part of the game, so I did it that way too. It means you should try harder to time your shots.</p>
<p>The bullet is just implemented as an <i>(x,y)</i> coordinate. When there is no bullet in play, the <i>y</i>
coordinate is set to -1.</p>
<p>Each frame, if there is a bullet in play, it's <i>y</i> coordinate is decreased by 1. 24a2 games run at 
24 fps by default (this can be changed, but I left it alone), so it would take 1 second for the bullet
to cross the entire screen.</p>
<p><h2>Shields</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2718"><img src="https://img.incoherency.co.uk/2718/thumb"></a></p>
<p>The shields in Space Invaders stop the aliens' bullets from reaching you, but they also stop your bullets
from reaching the aliens. The shields are depleted every time they get hit until eventually bullets can
pass straight through.</p>
<p>I implemented the shields by defining a fixed <i>y</i> coordinate and keeping track of the set of <i>x</i>
coordinates that still have shields on. When a bullet hits a shield, that <i>x</i> coordinate is removed from
the set and the bullet is destroyed, so that bullet didn't go through but the next one will.</p>
<p><h2>Aliens</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2719"><img src="https://img.incoherency.co.uk/2719/thumb"></a></p>
<p>The aliens move in a big pack, sliding left or right until they reach an edge of the screen, then dropping down
a row and sliding in the opposite direction. The aliens also speed up with each level (although, in my
implementation, top speed is reached at level 8 and every subsequent level is the same).</p>
<p>To make the game look a bit more interesting, I drew 3 different types of alien, and also gave each one a 2-frame
animation. It's difficult to evoke the image of the Space Invaders aliens in a 3x3 drawing, but I think it
kind of works.</p>
<p>Initially I just made the pack of aliens move through a fixed path, but I discovered that this does not faithfully
recreate the Space Invaders logic, because if you have shot all of the aliens on one side then the other aliens
need to move further before they reach the edge of the screen. This is important because it is a key part of
the strategy: you should shoot the aliens at the sides first to buy yourself time. So instead of a fixed path,
I just tested the position of each individual alien and reversed the direction of the pack if any one alien
reached the edge.</p>
<p>The player loses if any of the aliens get far enough down the screen to capture him. I think
technically you should only lose when one of the aliens hits you, but I just tested the <i>y</i>
coordinates of the aliens to see if any of them are far enough down.</p>
<p><h2>The aliens' bullets</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2720"><img src="https://img.incoherency.co.uk/2720/thumb"></a></p>
<p>The aliens occasionally shoot back at the player. I'm not sure if there should be some logic
to when the aliens start shooting, and whether or not that logic should be computed for
each alien individually, or for the aliens as a group. I just made it randomly fire
a bullet from a randomly-chosen alien on each frame with 20% probability. This means that the
rate that the aliens fire at you does not decrease as the number of aliens decreases. I did try
making each alien fire as an individual, but it didn't play very well because you etiher get way
too many bullets when all 12 aliens are alive, or not enough bullets when you're down to the last
handful.</p>
<p>I also didn't make the aliens pay any attention to whether or not the shot was going to go
anywhere near the player, but it seems fine.</p>
<p>If the player gets hit by an alien bullet, he dies. In the original game you have several lives
but I didn't bother with that. One hit and you're dead.</p>
<p><h2>Particle effects</h2></p>
<p>We have a working game now, but I wanted to provide a bit more action in the
graphics so I added some basic particle effects. This is used in the game to make
the aliens and the shields explode when they get hit by a bullet, and it's also used for
the confetti effect on the level transition and game over screens.</p>
<p>(Sorry, there's no screenshot because a static image can't really do it justice, but trying to
video record my screen and turn it into a GIF proved too time-consuming).</p>
<p>Particle effects are very easy to make and look pretty cool, even at 24x24. Each particle
just has a <i>(x,y)</i> coordinate, <i>(vx, vy)</i> velocity, and a colour. At each
frame, the particle's <i>(x,y)</i> coordinate is updated by adding on its velocity, and its
velocity is updating by adding gravity to <i>vy</i>:</p>
<p><pre><code>for (let i = 0; i &lt; particles.length; i++) {
        particles[i].x += particles[i].vx;
        particles[i].y += particles[i].vy;
        particles[i].vy += 0.1;
}</code></pre></p>
<p>The coordinates and velocities are stored as floating point values, with the coordinates
rounded to integer when they need to be drawn.</p>
<p>If a particle ever goes off the screen it is deleted immediately, but you could consider keeping
track of particles that go "above" the screen but are still within its width,
because you know gravity will eventually pull it back down.</p>
<p>Both the alien/shield explosions and the confetti are created the same way: given an <i>(x,y)</i>
coordinate at which to start the effect: just create 3 new particles, starting at <i>(x,y)</i>,
with random velocity. Alien/shield explosions take on the colour of the thing that is exploding,
and confetti takes a randomly-chosen colour.</p>
<p><h2>Game over screen</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2721"><img src="https://img.incoherency.co.uk/2721/thumb"></a></p>
<p>To support different types of screen, I created a variable called "<tt>gamestate</tt>" that references
the function to run for each frame. The main update function then just calls <tt>gamestate</tt>,
followed by drawing the particles.</p>
<p>Once the game is over, we transition into the "game over" state and from there we can never
transition out. If you want to play again, you need to refresh the page.</p>
<p>I created the writing in the GIMP with the pencil tool on a 24x24 canvas zoomed in pretty far, and
then manually wrote it out as a sprite:</p>
<p><pre><code>let gameoverSprite = makeSprite([
    " ###    #   #   # ####",
    "#      # #  ## ## #   ",
    "#     #   # # # # #   ",
    "#     #   # #   # ### ",
    "#  ## ##### #   # #   ",
    "#   # #   # #   # #   ",
    " ###  #   # #   # ####",
    "                      ",
    " ###  #   # #### #### ",
    "#   # #   # #    #   #",
    "#   # #   # #    #   #",
    "#   # #   # ###  #### ",
    "#   # #   # #    # #  ",
    "#   #  # #  #    #  # ",
    " ###    #   #### #   #",
]);</code></pre></p>
<p>It was just good luck that the 2 words are the same width, and that width fits neatly in a
24x24 canvas. The "E" is 1 character narrower than the other letters, but both words contain
exactly 1 "E" so it works out.</p>
<p>There are any number of ways to make the scrolling rainbow effect, and mine is bad. (But, in
short, I made a function that scans what has been drawn the "entire" screen and replaces every red
pixel with a colour selected from a function that creates the rainbow effect, and then to
get the rainbow effects you just plot red everywhere you want a rainbow, and then call that
function).</p>
<p>Just to make it a bit more interesting, there is some random confetti added using the
particle effects.</p>
<p><h2>Level transition screens</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2723"><img src="https://img.incoherency.co.uk/2723/thumb"></a></p>
<p>The level transition screen tells you the number of the level you're about to move to. I wrote
the "level" text the same way as the "game over" text, but slightly smaller because the
required letters allow it. (For example, it's hard to make a capital "G" that is only 3px wide).</p>
<p>I also added a couple of pixels of scrolling rainbow effect at the sides, and made the sprite
position shift around horizontally and scroll vertically, kind of like how the aliens move.</p>
<p>The level transition screen has a fixed timer of 60 frames, after which it reverts back to
the main game state so that the new level can begin playing.</p>
<p><h2>Fonts</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/2722"><img src="https://img.incoherency.co.uk/2722/thumb"></a></p>
<p>I wanted big numbers on the level transition screen, and big numbers are hard to draw by
plotting pixels by hand, so I copied the numbers from <a href="https://fontstruct.com/fontstructions/show/505936/11x7_smaller_dot_matrix">this 11x7 font</a>. I manually wrote them out as sprites, and then
when I need to draw the level number, I just draw the sprites for the appropriate digits. It
technically supports up to level 99 (i.e., up to 2 digits), but I don't know if anyone will
ever get as far as level 10.</p>
<p>You could use the same scheme to do arbitrary letters. This is the same way bitmap fonts
work anywhere.</p>
<p>And that's pretty much all there is to know about how I made 24invaders.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/24invaders.html</link>
   <guid>http://incoherency.co.uk/blog/stories/24invaders.html</guid>
   <pubDate>Sun, 28 Jun 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Keyboard switch progress &amp; test results</title>
   <description><![CDATA[Status on the 3d-printable keyboard switch is that the latest test managed 110,000 presses
before failure, on the spinning cam tester.]]></description>
   <content:encoded><![CDATA[<p>Status on the 3d-printable keyboard switch is that the latest test managed 110,000 presses
before failure, on the <a href="https://incoherency.co.uk/blog/stories/better-keyswitch-tester.html">spinning cam tester</a>.</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/DDa1zdZPm-o" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>The switch tester has been a surprisingly popular project, and has been featured on both <a href="https://hackaday.com/2020/06/23/switch-tester-servo-slaps-them-til-they-fail/">Hackaday</a>
and <a href="https://www.hackster.io/news/3d-printed-switch-and-tester-af9779a0da33">Hackster</a>. It's just a shame they picked up the servo-based tester instead of the <a href="https://incoherency.co.uk/blog/stories/better-keyswitch-tester.html">spinning cam</a>! I think
my <a href="https://incoherency.co.uk/blog/stories/keyswitch-tester.html">post about the servo-based tester</a> was a bit easier to digest. Less of a stream-of-consciousness.</p>
<p><h2>Switch design</h2></p>
<p>I made the changes described last time, which were:</p>
<p><ul>
<li>remove all unnecessary plastic between the contact wires, to stop it from levering up the contact plate and breaking contact</li>
<li>redesign the spring housing so it is a bit more suitable (short, and fits in a shelf, instead of tall and wedged into a big square opening)</li>
<li>use 2 spirals on the spring so that the forces balance and the plunger is pulled to the centre instead of off to one side</li>
<li>fillet the join between the spiral and its housing</li>
<li>remove unnecessary height from switch body</li>
<li>increase clearance around plunger</li>
<li>make the bottom narrower to accommodate the wires so that it fits in a 14mm hole even with the
wires poking out the side</li>
</ul></p>
<p>The switch looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2705"><img src="https://img.incoherency.co.uk/2705/thumb"></a></p>
<p>And to make it easier to see, the new spring looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2704"><img src="https://img.incoherency.co.uk/2704/thumb"></a></p>
<p>The spiral is made out of a series of semi-circles because it's easier that way, which is an idea
I got from the <a href="https://www.youtube.com/watch?v=wtjvWU0Ij-c">spiral cuts on the Antikythera
Mechanism</a>.</p>
<p>I wonder how easy it would be to use <a href="https://incoherency.co.uk/blog/stories/freecad-fea.html">Finite Element Analysis</a> to create an accurate animation of how the spring moves. Or even better, to get an accurate prediction
of the switch activation force. I'd probably need to fuse all the parts together at the places where they join, fix the outer case in space, and apply a downwards force on the plunger. It might be a bit
harder than that actually due to the preload on the spring (it is stretched out a bit even in the
rest position). Might be worth having a go.</p>
<p><h2>Switch testing</h2></p>
<p>I tried to drive the moisture out of my spool of black PETG by baking it in the oven for a few hours, but when I returned to get it out of the oven
I was disappointed to find that the temperature had been set to 100&deg;C instead of 50&deg;C. The spool was fused together and unusable. Bummer.
Oh, well, I'd been planning to order a spool of clear PETG soon anyway. In the mean time, I have a spool of "PIPG" or "post-industrial PET-G" that
I'm not particularly fond of because it tends to block the nozzle. I think "post-industrial" means it is made out of factory floor sweepings.
Here's a photograph of what I pulled out of the nozzle one time, taken with a USB microscope:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2594"><img src="https://img.incoherency.co.uk/2594/thumb"></a></p>
<p>It appears to show a small chunk of brassy-looking metal embedded in the filament, along with
a lot of other very fine metallic specks.</p>
<p>I've listed the setup of each of these tests with a small table, with the following fields:</p>
<p><table border>
<tr><th>Material</th><td>either the black PIPG or the clear PETG</td></tr>
<tr><th>Layer height</th><td>height of 3d printed layers (but note 1st layer is 1.5x as tall)</td></tr>
<tr><th>Contact plate thickness</th><td>thickness of flexible plastic plate that copper tape is stuck to</td></tr>
<tr><th>Activation position</th><td>amount of keystroke that has to be pressed before the contacts make contact</td></tr>
</table></p>
<p>Note that the <i>x</i>-axis scale varies each time, so you need to look at the numbers to compare
the graphs.</p>
<p><h3>1. PIPG switch, 50% activation, 0.15mm contact plate</h3></p>
<p><table border>
<tr><th>Material</th><td>PIPG</td></tr>
<tr><th>Layer height</th><td>0.1 mm</td></tr>
<tr><th>Contact plate thickness</th><td>0.15 mm (1 layer)</td></tr>
<tr><th>Activation position</th><td>50%</td></tr>
</table></p>
<p>I had previously been using a 0.25mm (2 layer) contact plate, but made a last minute change to 0.15mm because I thought making it more flexible would help. It did not help!</p>
<p>(Although the layer height is 0.1mm, the 1-layer contact plate is 0.15mm thick because the bottom layer is 1.5x the thickness of the other layers. I think
this is to aid bed adhesion, I left it alone because it's a default in the printing profile I'm using, but I'm not completely sure I agree with it.)</p>
<p><a class="img" href="https://img.incoherency.co.uk/2697"><img src="https://img.incoherency.co.uk/2697/thumb"></a></p>
<p>This is absolutely awful. Possibly the worst switch I have yet tested. The contact plate was way too floppy and never made reliable contact. Oh, well. Lesson learned:
the contact plate needs some stiffness. The only reason I let it run so long is because I was hoping it would wear in and start working properly.</p>
<p>The charting is basically the same as in the <a href="https://incoherency.co.uk/blog/stories/better-keyswitch-tester.html">last post</a>: as the motor rotates through 1 full revolution, the <i>y</i>-axis position sweeps from 0%
up to 100%. We plot a green line wherever the switch is detected as "on". And this time we also plot a red dot over the top of the green at every point the switch comes on/off apart from the first "on" and last "off" of
each revolution. This is a quick and easy visualisation of contact bounce, and also highlights any other discontinuities.</p>
<p>A good result would have a single solid green bar running from left to right with very little deviation up and down, and with minimal red marks.</p>
<p><h3>2. PIPG switch, 50% activation, 0.35mm contact plate</h3></p>
<p><table border>
<tr><th>Material</th><td>PIPG</td></tr>
<tr><th>Layer height</th><td>0.1 mm</td></tr>
<tr><th>Contact plate thickness</th><td>0.35 mm (3 layers)</td></tr>
<tr><th>Activation position</th><td>50%</td></tr>
</table></p>
<p>I re-printed the contact plate now even thicker than before. I actually can't remember if I re-printed the entire switch or just the contact plate. Regardless, I don't think I made
any substantial changes apart from the contact plate thickness.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2698"><img src="https://img.incoherency.co.uk/2698/thumb"></a></p>
<p>Much more promising. We got almost 11,000 presses before it went bad. There were a handful of "bouncy" presses after ~6,000,
but it's not obvious that these would have been
a big problem. The keyboard controller will need to have switch debounce logic anyway, so as long as it was just a small bounce and not a large discontinuity, I think it would be fine.</p>
<p>(I was actually surprised to see so little contact bounce. I had assumed that we would see multiple bounces on pretty much every keypress. Perhaps the Arduino just isn't fast enough to notice? Currently
the serial port runs at 9600 baud, and there are a few bytes transmitted on every state change. Serial communication blocks other processing, so it's possible that if I increased the serial port speed 
then I would detect more bounces, but it's inconvenient to change the speed because I'm reading the serial port with "<tt>cat</tt>" and I'm not good enough at "<tt>stty</tt>" to make it work at anything
other than 9600.)</p>
<p>Once the switch stopped working entirely, I took it out of the tester and inspected it to see what had gone wrong.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2703"><img src="https://img.incoherency.co.uk/2703/thumb"></a></p>
<p>The copper tape has broken! Now this I did not expect. With the constant flexing up and down, we have fatigued the copper to the point that it has failed on us. It makes sense really,
but I hadn't expected it because the copper tape felt so flexible.</p>
<p><h3>3. PIPG switch, 75% activation, 0.35mm contact plate</h3></p>
<p><table border>
<tr><th>Material</th><td>PIPG</td></tr>
<tr><th>Layer height</th><td>0.1 mm</td></tr>
<tr><th>Contact plate thickness</th><td>0.35 mm (3 layers)</td></tr>
<tr><th>Activation position</th><td>75%</td></tr>
</table></p>
<p>I spent quite a lot of time trying to work out what to do about the copper tape bending. Ultimately the solution is to find a way to allow the plastic to bend, and provide a spring force against the
copper, but keep the copper flat so that it does not wear out. I still haven't accomplished that in a way that is small enough to fit in a switch and simple enough to work reliably, so my "quick fix" was to move the
activation position down from the 50% point to the 75% point. That means that at the bottom of the 4mm stroke, the copper tape will only be flexing up by 1mm instead of 2mm, which should
prolong its life.</p>
<p>Moving the activation position is a compromise I don't really want to make, and I hope to be able to reverse it eventually, but I had to try it for now anyway.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2699"><img src="https://img.incoherency.co.uk/2699/thumb"></a></p>
<p>This is much better. We got over 40,000 presses before the switch showed any signs of trouble, and about 65,000 before it became unusably bad. Also note that the variation in activation
position is much lower here than in the previous test, presumably due to less stress on the flexible plate. At nearly 90,000 presses it stopped registering
entirely. At that point I inspected it to try and see what had happened, and was surprised to find nothing obviously wrong! I prodded and poked at it, and manually tested it a few times, and
nothing seemed wrong, so I put it back in the tester to see what would happen.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2700"><img src="https://img.incoherency.co.uk/2700/thumb"></a></p>
<p>To my surprise, it actually seemed pretty much fine again at first, albeit with a reduced activation range (I probably bent the plate while prodding at it). But it only took 5,000 presses
before it started acting strange, so something was obviously not right. Again I eventually switched it off and manually prodded it about, but couldn't find anything wrong
so put it back in the tester.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2701"><img src="https://img.incoherency.co.uk/2701/thumb"></a></p>
<p>And again it started off looking OK! But this time it only took just over 1,000 presses to break it, and not much more than 2,000 before it stopped registering presses at all. This time
I noticed that the copper tape had broken like before. But moving the activation position down seems to have helped a lot: we got between 40,000 and 70,000 good presses before failure, depending
on how generously you count them.</p>
<p><h3>4. Clear PETG switch, 75% activation, 0.50mm contact plate</h3></p>
<p>I switched to clear PETG here because this is when the spool of clear PETG arrived. In principle the clear material should be superior because it is not polluted with annoying
pigments messing up the mechanical properties of the plastic.</p>
<p><table border>
<tr><th>Material</th><td>Clear PETG</td></tr>
<tr><th>Layer height</th><td>0.2 mm</td></tr>
<tr><th>Contact plate thickness</th><td>0.50 mm (2 layers)</td></tr>
<tr><th>Activation position</th><td>75%</td></tr>
</table></p>
<p>Before printing this switch, I observed that the printing quality I got from my machine at 0.2mm layer height was quite superior
to the quality at 0.1mm layer height, so I moved to 0.2mm for this one. I think the difference is that under-/over-extrusion becomes
more significant at lower layer heights, whereas with higher layer heights there is more wiggle room. I don't think the change
in layer height should affect much. I also increased the thickness of the contact plate so that it would not be just a single layer.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2708"><img src="https://img.incoherency.co.uk/2708/thumb"></a></p>
<p>The slight blue tint caught me by surprise. I was printing with some blue PLA right before I loaded the clear PETG into the machine, and obviously
there was still some blue material lying around in the hot-end. It's not just a cosmetic problem, either: the presence of PLA mixed in with the
PETG will affect the mechanical properties, although I don't know by how much. Worth noting that it can take a long time to fully purge the nozzle
between filament changes, though.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2702"><img src="https://img.incoherency.co.uk/2702/thumb"></a></p>
<p>The copper tape broke at about 11,000 presses, which is about the same as we got with the activation position at 50%.</p>
<p>That's quite a disappointing result. I was expecting this switch to perform at least as well as the last PIPG one, because it was basically the same parts but in a different
colour. I don't know if I just got lucky with the last switch, or unlucky with this one, or whether the thicker contact plate somehow stresses the copper more, or something else.</p>
<p>I wondered what would happen if instead of replacing the contact plate, I just stuck another layer of copper over the top of the broken one.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2709"><img src="https://img.incoherency.co.uk/2709/thumb"></a></p>
<p>Over 110,000 presses before trouble started!
This is the best result so far. Is it just a matter of luck, or is "use 2 layers of copper tape" the magic formula to get more life out of it? More tests required.</p>
<p>(The single outlier near the start is from accidentally leaning on the cam and stalling the motor. The rotation position
is determined based on timing, on the assumption that the motor is spinning at a roughly constant speed. Stalling the motor halfway through a rotation throws off the timing for that rotation).</p>
<p>Interestingly, this switch failed the same way the <a href="https://incoherency.co.uk/blog/stories/keyswitch-failure.html">PLA one did</a>: the spring broke. The spring has 2 spirals, and both sides have broken. I expect the
trouble that developed around press 110,000 was caused by the spring breaking on one side but still
sort-of working on the other. Still, the switch had already been subjected to over 25,000 presses
before I put another layer of copper on it, so we know the spring was good for 135,000 presses
before it broke. I wonder if the PLA contamination made a material difference here.</p>
<p>I also noticed that the second layer of copper tape has split, but it at least lasted a lot longer
before doing so, and in fact the contact plate was still conductive from one side to the
other. I tested laying 2 pieces of copper
tape on each other with a small overlap, and found that they conducted perfectly well through
the adhesive
layer, so that gives us a second improvement with 2 layers of tape: not only do we reduce
the bend radius of the top (or, bottom) layer of tape, but we also get a second chance
at conducting electricity through the switch even if the top layer breaks!</p>
<p><h2>Another design</h2></p>
<p>I did design an alternative switch which uses 2 spiral springs and does not use a flat
contact plate. The idea here is that the spiral spring at the top is the main one that you feel
when pressing the switch, but when you reach the 50% position, the slotted hole in the plunger
engages a thin piece of copper wire and as you keep pressing down, that copper wire is then
pushed <i>away</i> from the main copper wire contacts. So this is push-to-break instead of
push-to-make, but that's not really important. The wire that bridges the 2 contacts is pressed
against them by preload on the bottom spiral spring. In principle it would work but I haven't yet got
it quite right. I haven't got enough preload on the lower spring so currently it doesn't make
good contact.</p>
<p>Here's a picture of the CAD model, but it's not very easy to understand:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2706"><img src="https://img.incoherency.co.uk/2706/thumb"></a></p>
<p>But if just using 2 layers of copper tape is an acceptable solution then I'd much sooner do that, as that
switch is easier to assemble and simpler in operation.</p>
<p><h2>Keycaps</h2></p>
<p>I have started experimenting with putting keycaps on the switches. It's the same model I <a href="https://incoherency.co.uk/blog/cad-dojo/stories/keycap.html">designed before</a>, but with a rectangular hole instead of a Cherry MX cross.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2707"><img src="https://img.incoherency.co.uk/2707/thumb"></a></p>
<p>The black one is PIPG, and has been sanded slightly, which didn't go very well. The blue one is PLA, and didn't print very well due to using 0.1mm layer height. The clear one is the clear PETG, and is the
best but is still a bit rough.</p>
<p><h2>Arduino library</h2></p>
<p>The <a href="https://www.arduino.cc/reference/en/language/functions/usb/keyboard/">Keyboard</a>
library for Arduino is very pleasant and easy to use. It abstracts away whatever you might
need to know to implement USB HID and just lets you say when you want keys to be pressed
and released. Perfect. I'll probably use it for the controller in the actual keyboard.
I just wish it would let you set a custom device string to show in
<tt>lsusb</tt>...</p>
<p>With keycaps and software pretty much figured out, and switches looking promising, I am almost
ready to make a
working macro keypad! If that goes well, I think I'll just need to work out what to do about
stabilisers on the spacebar etc., and come up with a sensible way to join 2 halves of the
keyboard case, and I can start putting together the actual keyboard.</p>
<p><h2>Next tests</h2></p>
<p>I intend to make a few more of the tester modules so that I can test several switches in
parallel, and then I'd like to print a few more switches and get some data with <i>N &gt; 1</i>
on how long they last with 1, 2, and 3 layers of copper tape, 50% and 75% activation position,
and possibly various thicknesses of contact plate.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/keyswitch-update.html</link>
   <guid>http://incoherency.co.uk/blog/stories/keyswitch-update.html</guid>
   <pubDate>Thu, 25 Jun 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>A better automatic keyboard switch tester</title>
   <description><![CDATA[Since breaking the last switch, I re-printed the same design in PETG
to see if it would last any longer, and it did! It reached over 100,000 presses under the gentle testing regime without
showing any failures, a big improvement over failing at 13,907.]]></description>
   <content:encoded><![CDATA[<p>Since <a href="https://incoherency.co.uk/blog/stories/keyswitch-failure.html">breaking the last switch</a>, I re-printed the same design in PETG
to see if it would last any longer, and it did! It reached over 100,000 presses under the gentle testing regime without
showing any failures, a big improvement over failing at 13,907.</p>
<p><h2>Harder testing</h2></p>
<p>The first tester was extremely gentle on the switches. Much more gentle than any human typist.</p>
<p>I stopped it after 100,000 presses and modified the Arduino program so that instead of letting go as soon as it detected that the switch had contacted, it would
instead press the switch all the way to the bottom of the stroke every time, and then measure whether it was successfully
contacted. I found that it started to fail after about 6,000 of the hard presses:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2686"><img src="https://img.incoherency.co.uk/2686/thumb"></a></p>
<p>Failure rate rose from 0% to 100% between the 6,000th and 10,000th hard press. The switch was actually still contacting successfully
as it was pressed down, but then as the plunger reached the bottom of the stroke, the conductive copper tape was being levered up and away from
the contacts, which was breaking the circuit. This problem would not have been discovered if I had just left it at gentle presses.</p>
<p>Here's an illustration of what's going on at the contacts of the switch:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2687"><img src="https://img.incoherency.co.uk/2687/thumb"></a></p>
<p>The red light shows when the two contacts are bridged together by the copper strip. Right at the bottom of the stroke, the red light
goes out because the copper strip is levered up and away from the contacts.</p>
<p>I don't know why this only became a problem after 6,000 presses (or, 106,000, including gentle ones). I expect it was just on the cusp of becoming a problem all along, and the copper
strip got bent up over time.</p>
<p>Here's a picture of the PETG switch in the tester, showing the copper strip at the bottom. Unfortunately it's hard to see much inside the switch because it is black
and shadowed:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2685"><img src="https://img.incoherency.co.uk/2685/thumb"></a></p>
<p><h2>New tester</h2></p>
<p>Using the servo to press a finger on the switch is the easy way to do it, but for improved speed we would want a spinning cam pressing down on the switch.
The reason I didn't do this at first is because I thought we might miss failed presses on the switch (e.g. if the motor does a complete revolution without pressing
the switch, how would the Arduino know whether it missed one or not?), and we might not notice if the activation position drifts over time.
<a href="https://www.stavros.io/">Stavros</a> suggested putting a small hole in the cam, shining an LED at the cam, and sensing each rotation by detecting when the light
reaches a photoresistor on the other side. This is a great idea, because then we get a very precise measurement of the motor RPM, we never miss a single revolution, and we can detect what
position the switch activates at by measuring the time between the start of the revolution and the switch activating.</p>
<p>LEDs and photoresistors seem a bit primitive to me, so I used a magnet and a hall effect sensor, but it's the same principle.</p>
<p>Here's a clip of the new tester, with one of the "kaiche" Cherry MX clone switches:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/D3xysvzHRxE" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>(The wiring is a mess but it seems to work OK for now).</p>
<p>I have provision here for 6 testing modules to be running simultaneously, off just the 1 microcontroller, before I run out of I/O pins. The motor has a switch on it so that I can disable an individual motor and hot-swap the switch
without interrupting the other tests. (I doubt I'll ever want to test 6 at once, but 2 at a time might be handy). The motor speed is controlled by adjusting the duty cycle of a PWM signal
which controls the L298N motor driver. In the video I was using a PID controller to try to target a precise motor RPM, but tuning it proved inconvenient so I am now just using a fixed duty cycle.</p>
<p>The new tester records the estimated rotation position of each time the switch turns on/off (based on timing - i.e. if the rotation takes 200ms and the switch comes on 50ms after the rotation started, then that's 25% into the rotation). A quick test of the commercial switch looked like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2688"><img src="https://img.incoherency.co.uk/2688/thumb"></a></p>
<p>Essentially, as the motor sweeps through a revolution, we are sweeping up the <i>y</i>-axis from 0% to 100%, and whenever the switch is "on" we plot a purple mark, and whenever the switch is off
we don't.
You can see that the switch comes on at about 42% into the rotation, and goes off at about 75%. This in contrast to the homemade PETG switch, after being broken by the "hard presses":</p>
<p><a class="img" href="https://img.incoherency.co.uk/2689"><img src="https://img.incoherency.co.uk/2689/thumb"></a></p>
<p>It comes on at about 47%, then goes off again at about 52%, then comes on at 63%, then goes off again at 68%. This is a great way to visualise problems with the switch.</p>
<p>Also, the old tester topped out at about 1 Hz for reasonable data, where the new tester can range from 2.8 Hz to 7.7 Hz depending on the PWM duty cycle.
The motor speed did vary a bit over time, so a PID controller might have been handy if properly tuned:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2690"><img src="https://img.incoherency.co.uk/2690/thumb"></a></p>
<p>But the detected on/off times of the switch seem to be relatively speed-invariant (as you'd expect):</p>
<p><a class="img" href="https://img.incoherency.co.uk/2691"><img src="https://img.incoherency.co.uk/2691/thumb"></a></p>
<p>Compared to the old tester, this is much better data, gathered much more quickly.
It's an improvement all around, except for how noisy it is. Last night I put a bucket over it and then put a dressing gown over the bucket to try and keep the noise down, which worked quite well.</p>
<p>Being able to automatically test the switches is great, because it quickly identifies problems to solve. If we were able to automatically test the <a href="https://incoherency.co.uk/blog/tags/lawnmower.html">mower</a>, maybe
that would have been more reliable during races. <a href="https://www.ferozsalam.com/">Feroz</a> suggested sticking some turf to a treadmill, but I think only as a joke.</p>
<p><h2>Switch improvements</h2></p>
<p>For the next attempt, I want to make the following improvements to the switch design:</p>
<p><ul>
<li>I should remove as much plastic as possible in between the copper wire contacts, to solve the problem of the copper strip getting levered up and breaking contact</li>
<li>currently the coil spring is mounted in a kind of pointlessly-tall 3-walled box that is wedged inside the housing, it should instead have a slim 4-walled box that slides into a "shelf" in the housing</li>
<li>the spring only has 1 coil at the moment, which means the forces are not balanced and it pulls off to one side as it is stretched; I want to have 2 nested coils attached at opposite sides so that the forces balance and it self-centres</li>
<li>Stavros said that his printer left the coil only barely attached to its pointlessly-tall box, I should fillet the join so there is more material there</li>
<li>the switch body is 2mm taller than necessary, as the plunger can never fully reach the bottom, I should just knock 2mm off</li>
<li>the plunger is a tight fit in its hole and requires manually cleaning up with a knife, I should increase the clearance</li>
<li>I should dry out my PETG a bit more, I left it in the oven for an hour at 60&deg;C and the quality improved a lot, but I think there is more moisture to drive out</li>
<li>the bottom of the switch should be a bit narrower so that it fits in a 14mm square hole even with the wires poking out the side, i.e. provide clearance for the wires</li>
</ul></p>
<p>Longer-term improvements would include:</p>
<p><ul>
<li>figure out how to use a coil spring to implement the flexible copper strip, it will probably be more reliable than a flat plate</li>
<li>figure out how to add a clicky tactile bump to the activation force, instead of just a linear spring</li>
</ul></p>
<p>I think that's all! As soon as I've got something that can last a sensible number of cycles in the new tester, the next step is to build a 4-switch "macro keypad" and see how it feels
to actually use. I'm considering using the Arduino <a href="https://www.arduino.cc/reference/en/language/functions/usb/keyboard/">Keyboard</a> library on an Arduino Pro Micro, but it
might be easier to just use <a href="https://qmk.fm/">QMK</a> and not write any of the firmware.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/better-keyswitch-tester.html</link>
   <guid>http://incoherency.co.uk/blog/stories/better-keyswitch-tester.html</guid>
   <pubDate>Sat, 20 Jun 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I broke my first 3D-printed keyboard switch</title>
   <description><![CDATA[Overnight I did my first test of a homemade keyboard switch on the automatic tester.
The spring in the switch broke after 13907 presses. That makes Martin our
competition winner, with a guess of 10000.]]></description>
   <content:encoded><![CDATA[<p>Overnight I did my first test of a homemade keyboard switch on <a href="https://incoherency.co.uk/blog/stories/keyswitch-tester.html">the automatic tester</a>.
The spring in the switch broke after <b>13907</b> presses. That makes <a href="https://falkus.co/">Martin</a> our
competition winner, with a guess of 10000.</p>
<p>I went to bed last night to the faint sound of the tester clicking the switch at about 1 Hz, but when I woke up this morning I was disappointed to find that
the sound had stopped! With the spring broken, the switch failed closed, which meant the tester never reached a state where
it was ready to do another cycle so it just sat there doing nothing.</p>
<p><h2>Switch</h2></p>
<p>This is the best picture I have of the switch:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2678"><img src="https://img.incoherency.co.uk/2678/thumb"></a></p>
<p>It's mounted in the tester, and you may notice the photgraph was taken after the spring had already failed.</p>
<p>This is the CAD model,
but it doesn't explain much because it doesn't show how the coil spring stretches out:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2679"><img src="https://img.incoherency.co.uk/2679/thumb"></a></p>
<p>It has a footprint of 14mm by 14mm, which is the same as a Cherry MX switch, although currently it
can not be pressed straight down into a 14mm square hole because the wires stick out the sides. Also
it is about twice as tall as a Cherry MX switch.</p>
<p>The switch is made of four 3D-printed parts (case, plunger, coil spring, flexible flat plate), 2
copper wires to provide contacts at the bottom, and some adhesive copper tape on the flexible
flat plate to connect the copper wires together when the plunger is pressed down.</p>
<p>When you press down on the plunger, you are stretching out the coil spring at the top. Once you
press far enough for the flexible flat plate to contact both of the wires, electricity can flow
and the switch is "on". If you want, you can keep pressing all the way to the bottom of the 4mm stroke,
stretching out the coil spring and bending up the flexible plate. Cherry MX switches
(all?) have a 4mm stroke, with activation at the halfway point, which is what I'm trying to mimic
here.</p>
<p>In the actual switch (but not shown in the CAD model), the coil spring is held away from its
resting position to provide some pre-load: if the coil spring were allowed to return to its
flat form, then the initial force required to move the plunger down would be 0, which would make
for an unusual typing experience. By forcing the spring to be pulling up on the plunger, we
create some initial force that must be overcome before the switch starts to move.</p>
<p>I got both the idea of using a flat coil spring and the idea of using adhesive copper tape
from <a href="https://www.youtube.com/channel/UCSsm4h2ccJMdR6bsAFyIu6A">Riskable 3D Printing</a>
on YouTube.</p>
<p>The spring eventually failed when the coil spring broke in half. I had actually expected that if
anything broke it would be the flat flexible plate because it is so thin. I think that because
the servo backs off as soon as it makes contact, there is never much force on the plate. If the
servo bottomed out the key instead of letting go, maybe it would be different.</p>
<p><h2>Test</h2></p>
<p>I have <a href="https://www.youtube.com/watch?v=a5cW9oIKtmA">a short clip of the tester with the homemade switch</a> in case you want to see
what the test setup looked like.</p>
<p>Obviously this is only a sample of 1, so we should be careful about stating any conclusions too strongly,
but it's at least more data than I had before.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2677"><img src="https://img.incoherency.co.uk/2677/thumb"></a></p>
<p>The activation points were <i>relatively</i> consistent for the first ~11300 presses (apart from a surprising bimodal distribution of
the release point for part of the test?), until something changed around the position
of the first red line, when the servo had to start pressing the finger a bit further before the switch would come on. Then around the
second red line at ~12400 presses, the activation position dropped off quite quickly, over the course of only a few tens of presses. I
expect both of these points correspond to some part of the spring starting to yield. It might have been interesting to leave a camera filming
the tester so that we can see exactly what it looks like at each press.</p>
<p>Finally, over the last 5 or 6 presses, the activation position dropped off precipitously, followed by the switch ceasing to function. This is when
the spring finally gave way completely.</p>
<p>Nearly 14k presses sounds OK until you consider that, if 1 in 5 keystrokes is a space, and you type at 120wpm, then you can expect to press the spacebar
120 times a minute. That means you'd reach 13907 presses of the space bar in just under 2 hours
of 120wpm typing. Not very good.</p>
<p>Just looking at the characters that are stored in my blog posts, I would have worn out my spacebar over
10 times, and would be on at least my third switch for each of e,t,o,a,i,n,s,r,h,l. Not to mention
backspace! So the switch definitely needs to work better before I make a keyboard.</p>
<p>Notable entries in the competition to guess how many presses it would take to break the switch
included a 17 (???) that was subsequently revised up to 900, a 5000 that was revised down to 200,
"tester fails before switch", and "jes gets impatient and redesigns the tester or the switch
before either one fails".</p>
<p><h2>Tester</h2></p>
<p>The tester presses the switch far too gently. It lets go as soon as it detects that the switch has made contact, whereas a human typist
is likely to smash the button all the way to the bottom of the stroke. Once I've made a switch that can withstand a sensible number
of gentle presses, I think I'll want to make the tester press it all the way to the bottom without letting go, to get a more reliable
test.</p>
<p><a href="https://www.ferozsalam.com/">Feroz</a> said the tester "types like his Mum".</p>
<p><a href="https://www.stavros.io/">Stavros</a> said the Tower Pro SG90 Micro Servos are not
very accurate, and indeed it seems that way. From the graph above, the random variation in activation positions is
about 10 microseconds of PWM pulse. There are 1000 microseconds in 180&deg; of rotation, so 10 us is equivalent
to 1.8&deg;. The contact point of the finger is 20mm from the centre of rotation, so a variation
of 10 us in PWM signal is equivalent to a variation of <i>20 * sin(1.8&deg;) = 0.6mm</i>. So
that's not very repeatable at all!
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/keyswitch-failure.html</link>
   <guid>http://incoherency.co.uk/blog/stories/keyswitch-failure.html</guid>
   <pubDate>Tue, 16 Jun 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Automatic keyboard switch tester</title>
   <description><![CDATA[I'm working on designing an open source 3D-printable keyboard switch at the moment,
with a view to eventually making my own mechanical keyboard using minimal off-the-shelf
components (just an Arduino, wire, and diodes, with homemade parts for switches, keycaps, and case). I have not
made a keyboard yet, but yesterday I made a device to test how many presses a switch can withstand
before it stops working.]]></description>
   <content:encoded><![CDATA[<p>I'm working on designing an open source 3D-printable keyboard switch at the moment,
with a view to eventually making my own mechanical keyboard using minimal off-the-shelf
components (just an Arduino, wire, and diodes, with homemade parts for switches, keycaps, and case). I have not
made a keyboard yet, but yesterday I made a device to test how many presses a switch can withstand
before it stops working.</p>
<p>Here's a video of it in action:</p>
<p><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/jl0PIKjTmjM" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p>All the code and CAD is on <a href="https://github.com/jes/keyswitch-tester">the github project</a>, so if you happen to want to make one, just follow the instructions in <tt>README.md</tt>. It's actually not very well designed, so if you can, you should design a better version (in particular,
try to position the servo so that it can move through its full range of motion instead of crashing into the frame).</p>
<p><h2>How it works</h2></p>
<p>It uses a servo to turn a robotic finger that slowly presses the switch down. When it detects that the switch has closed, it lights up the LED
and waits 100 ms for the contacts to settle, before slowly releasing the switch until it detects that the switch has opened again. At this point
it switches off the LED, resets the servo to the start position, and writes the measured activation and deactivation positions to the PC over the
USB serial connection. In the event that the servo reaches the configured end point without the switch closing, or reaches the configured
start point without the switch opening, it logs a failure instead. If the switch failed to reset, it won't start another cycle until it does.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2667"><img src="https://img.incoherency.co.uk/2667/thumb"></a></p>
<p>The switch is held in a separate part that is attached to the device with M3 screws. In principle, this makes it easy to make different holders
for different types of switch without having to rebuild the entire device. The first one I made fits Cherry MX switches, and here is holding
a "kaiche" (?) clone of a Cherry MX blue, which is the same as I used for the clock switch on the
<a href="https://incoherency.co.uk/blog/stories/autopatzer.html">automatic chess board</a>. (The tiny writing on the switch says "kaiche" as far as I can tell,
but all I can find about this word online is that it is the Chinese verb for "to drive a car").</p>
<p><a class="img" href="https://img.incoherency.co.uk/2669"><img src="https://img.incoherency.co.uk/2669/thumb"></a></p>
<p>I've started using <a href="https://www.prusa3d.com/prusaslicer/">PrusaSlicer</a> on the Anycubic i3 Mega, because it seems more maintained
than <a href="https://slic3r.org/">Slic3r</a> (which it is a fork of). In general it produces better quality parts than I ever managed with Slic3r,
but I have noticed some strange blobs on the outer surfaces of parts.</p>
<p>I think these are caused by the start/stop position in the layer, but I don't know why they're more pronounced than they used to be.</p>
<p>I made a small blunder in the CAD model for the switch holder: one of the screw holes does not have a hole in it! Fortunately 2 screws
proved sufficient to hold it securely.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2668"><img src="https://img.incoherency.co.uk/2668/thumb"></a></p>
<p>The switch was a very tight fit in the holder, I should have added a hole in the bottom so I can poke something up inside to push it out.</p>
<p>I used an Arduino "Pro Micro" for this project, mainly because I had it lying around already. Normally I'd use a Nano
because it's slightly smaller. One advantage of the Pro Micro is that it can act as a USB peripheral, which means I
might eventually be able to use it for the actual keyboard.</p>
<p>Lots of the code uses <tt>millis()</tt> for timing, and I did try to account for it overflowing after 2<sup>32</sup> ms (or ~49.7 days), but
don't know if I succeeded, and realistically will never find out.</p>
<p>I have found the Arduino sometimes spuriously resets itself. I do not know why. My best guess is that the servo draws too much power, which
causes a brownout. It worked for about 4 hours continuously yesterday until the first spurious reset, but was doing it every few minutes this morning.
Maybe the servo draws more power after it gets warm? If I can't convince myself that the resets are caused by something else, then I'll
try adding a separate power supply for the servo. Or maybe just tolerate it.</p>
<p><h2>Speed</h2></p>
<p>A servo is controlled by sending it a <a href="https://en.wikipedia.org/wiki/Servo_control#Pulse_duration">PWM signal</a> with the pulse width between 1000 microseconds and 2000 microseconds. The width
of the pulse tells the servo which position you want it to hold. The servo can't jump to a given position instantaneously, so once
you've requested a movement, it takes some time for the movement to actually happen, and during that time you don't know what position
the servo is at. For this reason, it's not enough to just ask the servo to move the finger to the maximum position, we have to move it in
small increments so that we always know what position the servo is at at the time the switch closes.</p>
<p>But how slowly do we need to move the servo? I tested a range of different speeds to see how fast I could go before the data
became worthless:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2656"><img src="https://img.incoherency.co.uk/2656/thumb"></a></p>
<p>The unit I've measured the servo speed in (<i>x</i>-axis) is "microseconds of pulse width per millisecond". That is, a speed of 1 us/ms allows the width of
the pulse in the PWM signal to change by 1 microsecond per millisecond of clock time, which is probably technically a unit-less value. Hope that makes sense.</p>
<p>The <i>y</i>-axis shows the value for the pulse width at which the switch turned on (blue) and off (orange). You can see that as the
speed goes up, the detection of the switch turning on or off gets delayed due to the time it takes for the servo to respond to our inputs. It
caps out at 1600 and 2000 microsecond pulses because those are the limits to the servo motion that I configured.</p>
<p>I chose 0.2 us/ms for the servo speed because it still gets reasonably useful data, without running unreasonably slowly.</p>
<p><h2>Switch testing</h2></p>
<p>I left it running overnight just to see what sort of data we get. I logged it with "<tt>cat /dev/ttyACM0 &gt; log</tt>".</p>
<p><a class="img" href="https://img.incoherency.co.uk/2660"><img src="https://img.incoherency.co.uk/2660/thumb"></a></p>
<p>The <i>x</i>-axis is roughly "time", except that the Arduino reset about 4 hours into the test, which killed the USB
serial connection, which killed my data collection until I switched it back on this morning. The Arduino resets and continues working
after about 1 second, but <tt>cat</tt> had exited so the data logging did not automatically resume. This point is indicated by the red
line on the graph at <i>x=14393</i>. I think we missed about 27,000 presses here, which is a shame but at least I know to watch out for that in the future
(i.e. have a program automatically reopen USB serial after it dies, and preferably fix whatever is making the Arduino reset).</p>
<p>You can see that when the logging resumed after the 8 hour gap, the range of activation positions had increased. Sometimes the finger
had to press slightly further before activating the switch. I don't know exactly why, but something must have worn in slightly over the course of the test.</p>
<p>I manually triggered 1 failure by holding the switch down after the
robotic finger let go, just to make sure it was still detecting failures correctly. Apart from that, across the ~23,000 presses that
were logged, there were 0 failures detected, which I suppose is what you'd expect from a commercial product.</p>
<p>To convert between times and press counts, we need to know how long the cycle time is. It actually takes a different amount of time
depending on the exact position at which the switch closes and opens, but I counted frames between when the LED switches on from one cycle
to the next in my video and found that the average cycle time was 24.5 frames, or about 940 ms. I should add timestamps to the logging
for next time.</p>
<p>It's likely that at least some of the change that was measured in this test comes from wear in the servo rather than the switch. That
might invalidate any conclusions you might try to draw about commercial switches, but I expect it will not be a problem when I am
testing homemade switches. <a href="https://www.ferozsalam.com/">Feroz</a> reckoned my switches would last about 2000 presses before
they stop working. If you want to submit your own guess, get in touch and I'll announce a winner once I've found out!</p>
<p>When I filmed the video of the tester (before I started logging the data), you can hear 2 distinct clicks when the switch is pressed. When pressing it by
hand I didn't notice this as it's difficult to apply such small precise movements. But as the plunger is pressed
almost
to the activation point, there's a first click, followed some time later by a second click when the switch actually closes. From the
animation of how a <a href="https://www.cherrymx.de/en/mx-original/mx-blue.html">Cherry MX blue</a> switch works, I think there should only be 1 click before the switch closes. The click should be audible when the white plastic piece pushes past the bump, allowing the spring contacts to close.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2661"><img src="https://img.incoherency.co.uk/2661/thumb"></a></p>
<p>(I did take a "kaiche" switch apart and verified that it works the same way as a Cherry MX).</p>
<p>And interestingly, after the 50,000 or so presses that my device has performed, the first click is now gone! I think some piece of plastic must
have been snagging, but has now worn down and the switch works more like how it's supposed to.</p>
<p><h2>Other people's 3D-printed switches</h2></p>
<p>The only other person I've come across working on 3D-printed keyboard
switches is <a href="https://www.youtube.com/channel/UCSsm4h2ccJMdR6bsAFyIu6A">Riskable 3D Printing</a> on YouTube. He is somewhat further along than me,
and his approach is slightly different. While I'm dead set on implementing
the contacts inside the switch I design, Riskable 3D is more interested in
making a high-quality switch regardless of off-the-shelf component usage,
and seems to be planning to use magnets and reed switches to sense when
the switch has been pressed. An interesting project nonetheless, although doesn't appear to have had any updates in the last couple of months.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/keyswitch-tester.html</link>
   <guid>http://incoherency.co.uk/blog/stories/keyswitch-tester.html</guid>
   <pubDate>Sun, 14 Jun 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Thoughts on laser level design</title>
   <description><![CDATA[A laser level is a device that projects a laser beam on
to a wall or similar, to help you position things level to the ground.]]></description>
   <content:encoded><![CDATA[<p>A <a href="https://en.wikipedia.org/wiki/Laser_level">laser level</a> is a device that projects a laser beam on
to a wall or similar, to help you position things level to the ground.</p>
<p>I have never actually seen or used one, but a <a href="https://duckduckgo.com/?q=laser+level&iax=images&ia=images">DuckDuckGo image search</a>
gives lots of examples. This picture pretty much illustrates the concept:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2643"><img src="https://img.incoherency.co.uk/2643/thumb"></a></p>
<p>(Although, for the purpose of this post, I'm only interested in the horizontal beam and not the vertical one - but a vertical beam could be implemented
exactly the same way).</p>
<p><h2>Basic design</h2></p>
<p>I first started thinking about laser levels a while ago when Jez got one and explained to me how great it was. Yesterday
I came back to them after
watching AlphaPhoenix's video on <a href="https://www.youtube.com/watch?v=exRgzJaB3D4">why smoke from a soldering iron
always goes towards your face</a>, in which he builds a device that projects a laser beam to illuminate a cross-section
of smoke in air. In principle it is actually quite easy: you just need to mount a mirror on a motor at 45&deg; and spin it really
fast, and then point a laser at the mirror. As the mirror spins, the laser beam is projected in different directions around
in a circle, sweeping out a plane in space. If you can make sure the plane is level to the ground, then you have
a functional laser level.</p>
<p>You could mount the laser directly on the shaft of the motor and not even need a mirror, but then you need to supply
power to the laser using <a href="https://en.wikipedia.org/wiki/Slip_ring">slip rings</a>, induction, batteries, or something else. Seems easier to just use a
mirror.</p>
<p>The idealised solution looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2639"><img src="https://img.incoherency.co.uk/2639/thumb"></a></p>
<p>(I drew it in <a href="https://inkscape.org/">Inkscape</a>).</p>
<p>The motor is mounted perfectly vertically, the laser beam is co-axial with the motor, and the mirror is at a perfect 45&deg;.
As the motor (and therefore the mirror) rotates, the laser beam sweeps out a horizontal plane parallel to the ground.</p>
<p>I got to thinking about how to actually build one in practice, which led to some observations about how the laser beam
could sweep through a path that is <i>not</i> a horizontal plane parallel to the ground.</p>
<p><h2>Sources of misalignment</h2></p>
<p>Without loss of generality, we'll treat the motor shaft as our reference axis, and assume that it always points vertically up.</p>
<p>It is possible for more than one of the following misalignments to be present at any given time (and in fact, in real life,
they are all always present to some extent), but it's relatively straightforward to imagine how they combine so I have not explicitly
shown this.</p>
<p><h4>Mirror angle</h4></p>
<p>If there is some misalignment of the mirror, then instead of a plane, the laser beam sweeps out a cone in space:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2641"><img src="https://img.incoherency.co.uk/2641/thumb"></a></p>
<p>If the mirror is <i>&theta;</i>&deg; away from the correct 45&deg;, then the cone of light drops (or rises) away from the intended horizontal plane
by <i>&frac12;&theta;</i>&deg;.</p>
<p>This is a problem, because if we're sweeping out a cone then points are illuminated at a different height above the
ground depending on how far away from the laser they are. Not very useful. A flat wall would be illuminated as a 
<a href="https://en.wikipedia.org/wiki/Conic_section">conic section</a>, which would be a hyperbola in the likely case, but possibly
a parabola or even an ellipse if either the device or wall is extremely far out of level!</p>
<p><a class="img" href="https://img.incoherency.co.uk/2645"><img src="https://img.incoherency.co.uk/2645/thumb"></a></p>
<p>(Picture from <a href="https://en.wikipedia.org/wiki/Conic_section#/media/File:Conic_Sections.svg">Wikipedia</a>).</p>
<p>The cone shown here is the cone of light from the laser, and the intersections of the flat coloured shapes with the cone represent the path that would be traced out on a flat
wall at different angles relative to the cone: the hyperbola is if the wall is steeper than the sides of the cone, the parabola is if the cone's sides are
parallel to the wall, the ellipse is if the cone's sides are steeper than the wall, and finally
the circle is achieved if the cone's axis is perpendicular to the wall surface.</p>
<p><h4>Laser axis</h4></p>
<p>If the laser is square to, but not co-axial with, the motor then the height of the illuminated point varies with the rotation angle.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2640"><img src="https://img.incoherency.co.uk/2640/thumb"></a></p>
<p>If the laser is off-axis by <i>x</i> mm,
then the line height varies by <i>2x</i> mm through its rotation (i.e. <i>&#177;x</i> mm from the centre line).
I assume it is a sine wave but have not proved it.</p>
<p>This is actually not that bad. It's quite reasonable to be able to align the laser within a few millimetres of the motor shaft, even if the
parts are made by hand. And unlike with angular misalignment, axial misalignment does not get worse as the projected point gets
further away (in fact, it gets better, because if you're further away then points that are a given distance apart on the wall are relatively closer
together in terms of rotation angle). It is unlikely that this misalignment would result in a laser level that is not usable, but for particularly
high-precision applications it might be something to consider.</p>
<p><h4>Laser angle</h4></p>
<p>I initially thought that if the laser were not square to the motor, this would give a cone as well, but as I was drawing the diagram
I realised that as long as the beam intersects the mirror at exactly the centre of rotation, then it would actually give a plane, just not level:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2642"><img src="https://img.incoherency.co.uk/2642/thumb"></a></p>
<p>If the laser is <i>&theta;</i>&deg; away from vertical, then the horizontal plane is tilted <i>&theta;</i>&deg; away from horizontal.</p>
<p>Interestingly, because this misalignment still results in the laser sweeping through a perfect plane, we could rotate the
entire apparatus, even though the laser is not aligned with the motor, and still get a perfectly functioning laser level:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2644"><img src="https://img.incoherency.co.uk/2644/thumb"></a></p>
<p>If I end up making one of these, then I would be tempted to tilt everything like this on purpose just for the extra challenge, because it's funny
& surprising that it can still work. You just need to make sure that the laser beam intersects the mirror exactly at the centre of rotation, which
could be achieved by allowing for some adjustment in the vertical position of the motor.</p>
<p><h2>Positioning</h2></p>
<p>Once we've achieved a motor-mirror-laser system that is all nicely aligned, then we need to be able to reliably position the device at a height
of our choice, and make sure the base is level.</p>
<p>To position it at a given height, you could put a <a href="https://en.wikipedia.org/wiki/Tripod_(photography)">1/4-20 UNC</a> female thread on
the bottom and mount it on a camera tripod.</p>
<p>To get it level, you could put a circular "bull's eye" <a href="https://en.wikipedia.org/wiki/Spirit_level">spirit level</a> on it and three
adjustable feet, and manually level it each time you want to use it. This is what I did with my <a href="https://incoherency.co.uk/blog/stories/pikon-telescope-hardware.html">telescope</a> and
it works but is annoying.</p>
<p>Fancy laser levels (including Jez's) are able to automatically level themselves as long as they are positioned within a few degrees of vertical. I have thought
of a couple of ways to achieve this.</p>
<p><h4>Gravity</h4></p>
<p>You could suspend the laser level from a short length of string, or a ball-and-socket joint, and let its weight pull it square like a
<a href="https://en.wikipedia.org/wiki/Plumb_bob">plumb bob</a>. This would
work as long as the centre of mass is perfectly in the centre (but that's easy to adjust). The potential problem is that the
motor might induce resonant vibration, which could result in a wobbly line, which would be more or less amusing depending on how
badly you want a straight line on the wall.</p>
<p>You could overcome the vibration either with some damping, or by using a locking ball-and-socket. With the locking ball-and-socket you
could just require the user to set the device up in place, wait for it to settle, and then tighten the joint so that it can't move before
switching the laser on. It might be easy enough, but I would be concerned about the ball getting moved slightly as the joint is tightened up,
and it does mean you have to commit to the height before you have even seen what the height is, so might actually involve multiple rounds of setting
the height and then checking it.</p>
<p><h4>2 servos and an accelerometer</h4></p>
<p>This is a rather "brute-force" solution to the problem: a 3-axis accelerometer can detect when it is not level (because it'll have some X or Y acceleration), and then we can use 2 servos
to level it in the XY plane. This would not be hard to implement, but it means adding a microcontroller to what would otherwise be a relatively mechanical project. Might be worth doing though.</p>
<p>Thanks for reading. I think that's all I have to say about laser level design for now.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/laser-level-design.html</link>
   <guid>http://incoherency.co.uk/blog/stories/laser-level-design.html</guid>
   <pubDate>Mon, 01 Jun 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to run a Cloud Desktop on any VPS, with SPICE</title>
   <description><![CDATA[SPICE is the graphical protocol used by QEMU since 2013. If you've started a VM
with QEMU, including with virt-manager or Gnome Boxes, then chances are you have used SPICE. It seems to be
the same concept as VNC but more efficient.]]></description>
   <content:encoded><![CDATA[<p><a href="https://www.spice-space.org/index.html">SPICE</a> is the graphical protocol used by QEMU since <a href="https://en.wikipedia.org/wiki/Simple_Protocol_for_Independent_Computing_Environments#Implementations">2013</a>. If you've started a VM
with QEMU, including with <tt>virt-manager</tt> or <a href="https://wiki.gnome.org/Apps/Boxes">Gnome Boxes</a>, then chances are you have used SPICE. It seems to be
the same concept as VNC but more efficient.</p>
<p>The SPICE website has the following diagram:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2637"><img src="https://img.incoherency.co.uk/2637/thumb"></a></p>
<p>And you may immediately see the problem with trying to run SPICE on a VPS: The "Spice Server" component in that diagram does not
run inside the VM, it runs as part of the virtualisation host, which means we don't have access to it. But we <i>can</i>
run <a href="https://www.spice-space.org/xspice.html">Xspice</a> which is a "standalone server that is both an X server and a Spice server".</p>
<p><h2>Why</h2></p>
<p>List of reasons to use a cloud desktop:</p>
<p><ul>
<li>more bandwidth than your local connection</li>
<li>more CPU and memory than your local machine</li>
<li>can't be stolen from your house/office</li>
<li>available everywhere in the world</li>
<li>totally isolated from your real desktop</li>
</ul></p>
<p>Admittedly, for the kind of work I do, SSH solves all of those just as well or better, but it would still be cool to be able to spin up a powerful desktop session
on-demand.</p>
<p><h2>How</h2></p>
<p>I basically followed <a href="https://s3hh.wordpress.com/2014/04/18/xspice-in-containers/">this post on running Xspice in containers</a>,
but ran it on a DigitalOcean VM instead of a container.</p>
<p>Start your VPS (here I assume running Ubuntu) and install <tt>Xspice</tt> and the <tt>ubuntu-desktop</tt> package:</p>
<p><pre><code>$ sudo apt install xserver-xspice ubuntu-desktop</code></pre></p>
<p>Once that's done, start a screen session and run:</p>
<p><pre><code>$ Xspice --password 123456 :0</code></pre></p>
<p>and in another window of screen:</p>
<p><pre><code>$ DISPLAY=:0 gnome-session</code></pre></p>
<p>Then, from your local machine, run <tt>spicy</tt> (which you can get with <tt>sudo apt install spice-client-gtk</tt> on Ubuntu 20.04),
connect to your VPS on port 5900, and type in the password you gave to <tt>Xspice</tt>. You should now be connected to an Ubuntu desktop running in the cloud!</p>
<p><a class="img" href="https://img.incoherency.co.uk/2638"><img src="https://img.incoherency.co.uk/2638/thumb"></a></p>
<p>If you like it and want to use it more, then you should probably follow the instructions in the <a href="https://s3hh.wordpress.com/2014/04/18/xspice-in-containers/">Xspice in containers</a>
post about disabling the SPICE password, restrict it to localhost-only with iptables or firewalld, and connect to it with an SSH tunnel.</p>
<p><h2>Why not</h2></p>
<p>Before I'd actually want to use this, we'd need to solve the following problems:</p>
<p><ul>
<li>It doesn't use the proper Ubuntu theme for some reason? It's kind of a mix between Ubuntu's Gnome and standard Gnome. I tried <tt>--session=ubuntu</tt> but it made no difference. Not sure what's missing.</li>
<li>There's no audio.</li>
<li>The screen does not automatically resize to match the viewer. You can manually resize it using the "Display Settings" panel, but only to some pre-defined sizes, so you end up with borders
around the screen, or the screen stretched to fit your real screen.</li>
<li>Latency is too high for it to be a pleasant desktop experience.</li>
</ul></p>
<p>I did try running <a href="https://freecadweb.org/">FreeCAD</a> in my VM and looking at some of the <a href="https://incoherency.co.uk/blog/stories/autopatzer.html">Autopatzer</a> parts.
The parts aren't that complicated, but they're about as complicated as anything I want to model in FreeCAD and it worked well, especially considering that
the rendering was being done in software due to the absence of any kind of GPU. The latency was still annoying, but the frame rate was great.</p>
<p>It would be perfectly within the realms of feasibility to work out what Ubuntu does to make its theme look right,
to stream audio over a separate channel, and to write a client that communicates the screen dimensions to the server. There is actually SPICE support to set screen size with
<tt>spice-vdagent</tt> but it seems to be aimed more at virtio-based display devices, so I'm not sure whether we'd be able to use it with Xspice inside a VPS. But we could
easily do it with our own protocol and xrandr.</p>
<p>Overall I think the latency is the unsolvable problem here. I think we just need about 1 order of magnitude improvement in network latency and then this would be
perfectly usable. Given speed-of-light limits, this probably means we need data centres nearer people's homes.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/cloud-desktop.html</link>
   <guid>http://incoherency.co.uk/blog/stories/cloud-desktop.html</guid>
   <pubDate>Thu, 21 May 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>An easy way to package Perl programs</title>
   <description><![CDATA[The right way to package Perl programs is with RPM, or DEB, or on CPAN with
ExtUtils::MakeMaker or similar. But this is a hassle.]]></description>
   <content:encoded><![CDATA[<p>The <i>right</i> way to package Perl programs is with RPM, or DEB, or on CPAN with
<tt>ExtUtils::MakeMaker</tt> or similar. But this is a hassle.</p>
<p>For really-simple Perl scripts, where everything is in one file, we can just distribute that
single file and tell people to put it in <tt>~/bin</tt> or <tt>/usr/bin</tt> or wherever they want.</p>
<p>The difficulty comes when your Perl program is slightly more complicated than a single file, and
some of the code is spread across a small handful of modules. We're not quite at the level where
we want an entire build and packaging infrastructure around our project, but we want to be able
to distribute it for others to use. Telling people to copy the contents of <tt>lib/</tt> into
their system's local Perl library directory is not really reasonable.</p>
<p>My solution: concatenate all your modules together into a single file and ship it as a single-file script!
I know, I know. Hear me out here.</p>
<p>It's <i>almost</i> as simple as "just concatenate everything into one file", but with 2 issues:</p>
<p><ol>
<li>all our "<tt>use MyApp::Foo;</tt>" lines won't work because Perl can't find <tt>MyApp/Foo.pm</tt> anywhere in <tt>@INC</tt></li>
<li>we need a shebang at the start with "<tt>#!/usr/bin/perl</tt>"</li>
</ol></p>
<p>But these are easily solved. Example Makefile:</p>
<p><pre><code>build/myapp: lib/MyApp/*.pm lib/MyApp.pm bin/myapp
    mkdir -p build/
    echo "#!/usr/bin/perl" > build/myapp
    cat $^ | sed 's/^use MyApp/import MyApp/' >> build/myapp
    chmod +x build/myapp
    
install: build/myapp
    install -m 0755 build/myapp /usr/bin/myapp
    
clean:
    rm -f build/myapp</code></pre></p>
<p>That concatenates all the library files first, followed by the main program. This means when the code is executed it will
run through each of the packages before reaching the main code, just as it would if they were imported with <tt>use</tt>
statements. To solve problems with all of the "<tt>use MyApp::Foo</tt>" lines we can just replace <tt>use</tt> with
<tt>import</tt>. And we can manually add a shebang at the start.</p>
<p>I used this idea for <a href="https://github.com/jes/ngindock">Ngindock</a> and it seems to work OK for that.</p>
<p><h3>Pros</h3></p>
<p>It's quick and easy and has no external dependencies.</p>
<p>You can still develop the program as separate modules.</p>
<p>There is precedent from the JavaScript ecosystem (although, maybe this is a con not a pro).</p>
<p><h3>Cons</h3></p>
<p>People will think you're crazy and/or stupid.</p>
<p>Your modules won't go into anywhere in <tt>@INC</tt> so they won't be available for other programs to use.</p>
<p>There's no dependency management.</p>
<p>The <tt>sed</tt> regex to match "<tt>use MyApp</tt>" anchors at the start of the line, so if you do anything
weird like:</p>
<p><pre><code>use Important::Module; use MyApp::Foo;</code></pre>
or
<pre><code>     use MyApp::Foo;</code></pre></p>
<p>Then it won't replace <tt>use</tt> with <tt>import</tt>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/perl-packaging.html</link>
   <guid>http://incoherency.co.uk/blog/stories/perl-packaging.html</guid>
   <pubDate>Sat, 16 May 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Zero-downtime Docker container deployments with nginx</title>
   <description><![CDATA[Docker doesn't let you reassign port mappings while containers are running. That means if you want to deploy
a new version of your application, you need to stop the old one and then start the new one, and there is a
brief period of downtime in between. I wrote Ngindock to solve
this problem.]]></description>
   <content:encoded><![CDATA[<p>Docker doesn't let you reassign port mappings while containers are running. That means if you want to deploy
a new version of your application, you need to stop the old one and then start the new one, and there is a
brief period of downtime in between. I wrote <a href="https://github.com/jes/ngindock">Ngindock</a> to solve
this problem.</p>
<p>I recently got sold on Docker and am in the process of Dockerising many of the services I run. Currently most of the
stuff I've written uses <a href="https://mojolicious.org/">Mojolicious</a> and runs under <a href="https://mojolicious.org/perldoc/Mojo/Server/Hypnotoad">hypnotoad</a>,
behind nginx as a reverse proxy. To hot-deploy a new version of the application, I can just:</p>
<p><pre><code>$ hypnotoad app</code></pre></p>
<p>And hypnotoad will replace itself with a version running the new code, with no downtime.</p>
<p>This doesn't work very well in the Docker case, because the Docker images are meant to be immutable and therefore
the version of the code that hypnotoad has access to is also immutable. There are various solutions for downtime-free
deployments for people who are a bit more Cloud Native than me, including <a href="https://docs.traefik.io/">Traefik</a>,
<a href="https://kubernetes.io/">Kubernetes</a>, and <a href="https://docs.docker.com/engine/swarm/">Docker Swarm</a>.</p>
<p>I wanted something that would be minimally disruptive to all of my existing non-Dockered services. The solution I had in mind was:</p>
<p><ol>
<li>start a new container running the new image, listening on a different port</li>
<li>rewrite the nginx config to direct traffic to the new port</li>
<li>reload nginx to make it use the new config</li>
<li>stop the old container</li>
</ol></p>
<p>I couldn't find a tool that did this, so I made one. It seems to work OK but I would definitely recommend
caution before using it on anything you care about. The <a href="https://github.com/jes/ngindock">README on github</a>
has relatively detailed instructions on how it's used and configured, but in brief:</p>
<p><ul>
<li>make a file in your deployment directory called <tt>ngindock.yaml</tt>, describing the Docker image and container
names, port numbers, etc.</li>
<li>run <tt>ngindock</tt> whenever you want to trigger a fresh deployment</li>
</ul></p>
<p>It aims to leave your <tt>nginx.conf</tt> completely unchanged (including comments and whitespace) apart from the port
number. If it fails at this, that's a bug, please open a github issue.</p>
<p>If you want to give it a try, clone the <a href="https://github.com/jes/ngindock">https://github.com/jes/ngindock</a> repo
and follow the instructions in the <tt>demo/</tt> directory.</p>
<p>Example <tt>ngindock.yaml</tt>:</p>
<p><pre><code>nginx_conf: /etc/nginx/conf.d/app.conf
nginx_upstream: app
ports: [3000,3001]
container_port: 3000
image_name: my_image
container_name: my_container
health_url: /</code></pre></p>
<p>Example session with "-v":</p>
<p><pre><code>$ sudo ngindock -v 
[Thu May 14 17:20:31 2020] plan to move from port 3000 to 3001
[Thu May 14 17:20:31 2020] start container listening on 3001...
[Thu May 14 17:20:31 2020] started container my_container_ngindock_new
[Thu May 14 17:20:31 2020] wait for container health check...
[Thu May 14 17:20:32 2020] update nginx to direct traffic to port 3001...
[Thu May 14 17:20:32 2020] remove old container if it exists...
[Thu May 14 17:20:32 2020] stopping container my_container
[Thu May 14 17:20:33 2020] removing container my_container
[Thu May 14 17:20:33 2020] rename my_container_ngindock_new to my_container...</code></pre>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/ngindock.html</link>
   <guid>http://incoherency.co.uk/blog/stories/ngindock.html</guid>
   <pubDate>Thu, 14 May 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Autopatzer: my automatic chess board</title>
   <description><![CDATA[My automatic chess board (the "Autopatzer") has reached the point where last night I was able to
play its first online game against a real person using lichess's Boards API.]]></description>
   <content:encoded><![CDATA[<p>My automatic chess board (the "Autopatzer") has reached the point where last night I was able to
play its first online game against a real person using lichess's <a href="https://lichess.org/blog/XlRW5REAAB8AUJJ-/welcome-lichess-boards">Boards API</a>.</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/8ScFtkWvHW8" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p>
<p><a href="https://padlock.argh.in/">Feroz</a> described playing online chess over a physical board as "very lockdown chic", which I liked.</p>
<p>And, since a lot of people ask:</p>
<p><blockquote><b><i>patzer, n.</i></b> A poor or amateurish chess player.</blockquote></p>
<p><h2>Overview</h2></p>
<p>To actuate output moves, the board has X and Y axis <a href="https://en.wikipedia.org/wiki/Linear_stage">motion stages</a>, driven by NEMA17 stepper motors with GT2 timing belts, with an electromagnet
mounted on the carriage. It's basically like a 3d printer but with no Z axis, and with an electromagnet instead of a hot-end. To detect input moves, the board has a
hall-effect sensor underneath each square.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2577"><img src="https://img.incoherency.co.uk/2577/thumb"></a></p>
<p>The electronics are controlled by a Teensy 3.2, which speaks to a Raspberry Pi over USB serial. All of the source code (and CAD models, and PCB design) are in the
<a href="https://github.com/jes/autopatzer">jes/autopatzer</a> github repo.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2616"><img src="https://img.incoherency.co.uk/2616/thumb"></a></p>
<p><a href="https://milesarmstrong.co.uk/">Miles</a> is currently furloughed from his day job and was looking for a project to do, so he has been working on
the <a href="https://www.electronjs.org/">Electron</a> app that provides the GUI displayed on the touchscreen.</p>
<p>You could argue that the board-related logic could have been written in Javascript and then it could be in the same program as the Electron GUI. You'd be right.
I just found it more convenient to do the board logic in Perl.</p>
<p>The Raspberry Pi is mounted in a 3d-printed case at the side of the board and has a 5-inch 800x480 HDMI touchscreen:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2623"><img src="https://img.incoherency.co.uk/2623/thumb"></a></p>
<p>The touchscreen is there to allow seeking a game, offering/accepting a draw,
and resignation, and displaying clocks, move history, and current input move. There is a Cherry MX blue keyswitch mounted on the plastic case which provides basically the function of a "clock button":
having moved a piece, the user must hit the button to confirm the move and end the turn. Hitting the button triggers an interrupt on one of the GPIO pins (which I initially
tried to detect in Perl, but <a href="https://metacpan.org/pod/RPi::Pin">RPi::Pin</a> was causing segfaults, hence the Python program).</p>
<p><h2>Painting the squares</h2></p>
<p>I first covered the board surface in masking tape.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2584"><img src="https://img.incoherency.co.uk/2584/thumb"></a></p>
<p>Then marked out the grid and cut every other square out.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2585"><img src="https://img.incoherency.co.uk/2585/thumb"></a></p>
<p>Then spray-painted the whole thing black.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2586"><img src="https://img.incoherency.co.uk/2586/thumb"></a></p>
<p>Then peeled off the rest of the masking tape.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2587"><img src="https://img.incoherency.co.uk/2587/thumb"></a></p>
<p>I don't think this worked spectacularly well, quite a lot of paint seems to have seeped under the tape and messed up adjacent squares. It's adequate though.
After this, I sprayed several coats of lacquer over the top of the board to make it look nicer, and to reduce friction for moving the pieces.</p>
<p><h2>Electronics</h2></p>
<p><h3>Inside the board</h3></p>
<p><a href="https://www.pcbway.com/">PCBWay</a> generously supplied me with free PCBs for this project (I only needed 1, but their minimum order is 5).
The PCBs are excellent quality as expected, not obviously any different to ones I've ordered from JLCPCB in the past. I did have to pay an
unexpected fee of &pound;18 to DHL before I could receive them. It's not entirely obvious what this fee was for, I don't think it was import
duty. DHL called it an "advanced payment".</p>
<p><a class="img" href="https://img.incoherency.co.uk/2628"><img src="https://img.incoherency.co.uk/2628/thumb"></a></p>
<p>And here it is installed:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2617"><img src="https://img.incoherency.co.uk/2617/thumb"></a></p>
<p>I realised after I started putting it all together that I had failed to include any pads on the PCB for power to the hall-effect sensors.
I solved this by supergluing a 2-pin right-angle header to the board and running wires to where I needed them. It's hidden by the lower stepper
motor cable in the photo so you'll just have to imagine.</p>
<p>The 2 red circuit boards are A4988 stepper motor drivers. I'm considering replacing these with some Trinamic drivers for "silent" stepper operation,
if I can find some drop-in replacements that are cheap and pin-compatible. The red jumpers next to the red PCBs are selecting the microstepping
mode. I originally thought I would not use any microstepping but ended up adding what I think is 1/2 microstepping, so I'm glad I bothered to add
the jumper pins. The green jumper towards the bottom right is joining together the positive voltage for the stepper motors and the 
electromagnet. I have the capability to run them at different voltages (by removing the green jumper and adding a different supply voltage)
but for now they're both running at 19v from an old laptop power supply.</p>
<p>The left half of the PCB has 8 headers for hall-effect sensor signals, and 8 corresponding CD4051 8-to-1 analogue multiplexers. The Teensy does
not have 64 analogue inputs, so in order to read from 64 analogue signals, I use 8 multiplexers each with 8 signals. This takes up 3
digital outputs (used to select which channel to read, which is wired the same to each multiplexer), and 8 digital inputs (carrying the
currently-selected signals from the multiplexers). The hall-effect sensors plugs are all labelled so that if I ever unplug them I have
half a chance of getting them all back in the right order.</p>
<p>The grey wire running off towards the bottom-right of the picture is going to the electromagnet. I am slightly concerned that it is too thin
for the amount of current it carries, but since it is only on for a few seconds at a time I don't think it will be a problem. I actually put
a failsafe in the Arduino code to switch the electromagnet off after 20 seconds of inactivity to prevent accidental damage. It would still
be possible to damage it deliberately, for example by sending a command to switch the electromagnet on every 20 seconds. But if you're going to do that
you can just set the whole thing on fire with a blowtorch anyway.</p>
<p><h3>Raspberry Pi</h3></p>
<p>Here's the CAD model of the case around the Raspberry Pi:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2619"><img src="https://img.incoherency.co.uk/2619/thumb"></a></p>
<p>The rectangular piece at the left is a cover for the Pi's IO ports. It has a hole for a small magnet to hold it against the casing of the USB ports.</p>
<p>The HDMI touchscreen is held inside the top piece of the case with 4 3d-printed hold-down clamps, and the Pi is held to the
touchscreen with a combination of the HDMI connector and (not pictured) the GPIO header plug on the back of the touchscreen:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2621"><img src="https://img.incoherency.co.uk/2621/thumb"></a></p>
<p>In that picture we also see a pull-up resistor for the keyswitch, between one of the GPIO pins and +5v, and a 2-pin header with 1 pin to ground and 1 pin to
a GPIO pin, for the keyswitch (visible at bottom left of the Pi; it's plugged into the GPIO header on the top side of the board). There's also a MicroUSB
cable soldered on to the pins for one of the USB ports, this is for speaking USB serial to the Teensy, and is done that way because there's not enough room
for a proper MicroUSB plug. Similarly, power input to the Pi is provided by wires soldered to the board at the bottom. The USB port used for the
connection to the Teensy is of course no longer usable as an actual port, so I have put a small 3d printed bung in it to prevent any trouble.</p>
<p>There are corresponding ends for each of these connections inside the other half of the case:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2622"><img src="https://img.incoherency.co.uk/2622/thumb"></a></p>
<p>Not the best quality 3d printing but it'll do.
The green PCB here is a <a href="https://en.wikipedia.org/wiki/Buck_converter">buck converter</a> to convert 19v from the power supply down to 5v for the Pi.</p>
<p><h2>Magnets</h2></p>
<p>Selecting magnets is one of the trickiest parts of the whole project.
You need to put a magnet in the base of each piece, and the magnets need to be weak enough that 2 pieces can pass by each other without repelling,
and strong enough that they can be grabbed by the electromagnet and sensed by the sensors. Tying into this is the mass of your lightest and heaviest
piece (because light pieces are more easily repelled, and heavy pieces are harder for the electromagnet to move), the size of the squares (because
that sets the distance between the pieces), the thickness of your board (because a thicker board puts the sensor further away from the piece), and
the properties of the electromagnet.</p>
<p>I ended up with:</p>
<p><ul>
<li>cylindrical neodymium magnets, 6mm diameter, 6mm height, "N50" strength</li>
<li>48mm squares</li>
<li>SS49E analogue hall-effect sensors</li>
<li>6mm MDF board (so the top of the hall sensor is 6mm away from the bottom of the magnet)</li>
<li>Arbitrary no-name electromagnet, with the top of the electromagnet about 3mm from the bottom of the board (so 9mm from the bottom of the piece)</li>
</ul></p>
<p>I would not necessarily recommend using analogue hall-effect sensors. I thought this would be a good idea because it would allow me to tune the
signal threshold to adjust the sensitivty, but it just means it's tricky to pick a threshold value that works well with
unstable power supply voltage. I think digital hall-effect sensors would work better. If you used reed switches instead you would
be able to wire them up like a <a href="https://en.wikipedia.org/wiki/Keyboard_matrix_circuit">keyboard matrix</a> and reduce
both the amount of wiring and the number of IO pins required. I don't know how sensitive reed switches are, and
they strike me as unreliable, so I did not try it, but it might be a better way.</p>
<p>I took my pieces from a magnetic chess set that I already owned, but the original magnets were too weak. I removed the original magnets,
but the holes were too large for my 6mm magnets, so I 3d printed some sleeves which push-fit into the bottom of the piece, and then the
6mm magnets push-fit into the sleeves:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2625"><img src="https://img.incoherency.co.uk/2625/thumb"></a></p>
<p><h2>Still to do</h2></p>
<p>We still have a lot of work to do to get the GUI prettier and more feature-complete. I need to get the Pi to boot all the way to the full-screen GUI
without any user interaction required. I'd like to add some guards to the inside of the board to prevent the motors from being catastrophically driven into
the PCB in the event that the homing doesn't work properly. I'd like to add limit switches instead of "crash-homing", because while crash-homing is a funny idea, and
works OK for a floppy drive, it is slightly too violent to be acceptable in a device of this size. The perl library doesn't yet understand en passant inputs.
The stepper motors whine slightly at idle even if they're not moving. Not sure why. I get an intermittent under-voltage warning on the Pi after it has warmed
up a bit. I'm not sure if I need to adjust the voltage on the buck converter, or just add a capacitor across its output, perhaps both.</p>
<p>If you want to help with any of this, or build your own board, please get in touch: <a href="mailto:james@incoherency.co.uk">james@incoherency.co.uk</a>, I'd
love to hear from you. If others want to build one of these, then I'd be interested in producing an open-source design with decent CAD models
and repeatable build instructions. Everything is in <a href="https://github.com/jes/autopatzer">the github repo</a> already, but it's not exactly easy
to work with if you don't already know how.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/autopatzer.html</link>
   <guid>http://incoherency.co.uk/blog/stories/autopatzer.html</guid>
   <pubDate>Wed, 06 May 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>YubiKey SSH authentication: the easy way</title>
   <description><![CDATA[I bought a YubiKey quite a while ago, with the intention
of using it for SSH authentication, but never got to
the point of actually using it because I found it too hard to set up.
Today I had another go
and managed to get it working using the "PIV" mode.]]></description>
   <content:encoded><![CDATA[<p>I bought a <a href="https://www.yubico.com/">YubiKey</a> quite a while ago, with the intention
of using it for SSH authentication, but never got to
the point of actually using it because I found it too hard to set up.
Today I had another go
and managed to get it working using the <a href="https://developers.yubico.com/PIV/Guides/SSH_with_PIV_and_PKCS11.html">"PIV" mode</a>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2610"><img src="https://img.incoherency.co.uk/2610/thumb"></a></p>
<p>(If you read this and you think "I've been using a YubiKey for ages and my way is easier than
this", then chances are you're more of an expert than me, and what's easy for you might not be
easy for me).</p>
<p><h3>Requirements</h3></p>
<p>I only wanted
SSH authentication and found that the PIV way was easier than the others I tried.
Lots of people seem to use their YubiKey via GPG. I couldn't get this to work and gave up.</p>
<p>The PIV method does not require any special
support from the SSH server. You just write the public key into <tt>~/.ssh/authorized_keys</tt>
on the remote end and then you can SSH in, authenticated by your YubiKey.</p>
<p><h3>Set it up</h3></p>
<p>You mostly want to <a href="https://developers.yubico.com/PIV/Guides/SSH_with_PIV_and_PKCS11.html">follow
YubiCo's tutorial on using PIV for SSH through PKCS #11</a>, which I would modify so that it reads as follows:</p>
<p><b>Step 1</b>: Install the dependencies:</p>
<p><pre><code>$ sudo apt install yubico-piv-tool ykcs11</code></pre></p>
<p><b>Step 2</b>: Generate a key on the YubiKey. YubiCo suggest slot 9a but note that "any slot should suffice". I don't
know what a slot is or what the options are, so I chose 9a.</p>
<p><pre><code>$ yubico-piv-tool -s 9a -a generate -o public.pem</code></pre></p>
<p><b>Step 3</b>: Change the PIN. The default YubiKey PIN is 123456. Interestingly I had already changed the PIN while trying to get the
GPG stuff to work, but found that the PIV mode PIN was still 123456. I believe that the PIV
mode is separate software running on the YubiKey and therefore has a separate PIN.</p>
<p>Good to know is you can actually use (relatively?) arbitrary characters in the PIN, it does not have to be numeric.</p>
<p><pre><code>$ yubico-piv-tool -a change-pin</code></pre></p>
<p>There seems to be a limit on the allowable length. I first tried to set a long password and was told
"Retrieving new pin failed.", so if you get that message, you just need to pick a shorter password.</p>
<p><b>Step 4</b>: Create a certificate for the key and import it. YubiCo state that "The only use for the X.509 certificate is to
satisfy PIV/PKCS #11 lib. It needs to be able to extract the public-key from the smartcard, and to do that through the X.509 certificate."</p>
<p><pre><code>$ yubico-piv-tool -a verify-pin -a selfsign-certificate -s 9a -S "/CN=SSH key/" -i public.pem -o cert.pem
$ yubico-piv-tool -a import-certificate -s 9a -i cert.pem</code></pre></p>
<p>You won't need <tt>cert.pem</tt> after this.</p>
<p><b>Step 5</b>: Add <tt>libykcs11</tt> to your SSH agent:</p>
<p><pre><code>$ ssh-add -s /usr/lib/x86_64-linux-gnu/libykcs11.so</code></pre></p>
<p><b>Step 6</b>: You can now copy your public key to a remote host with <tt>ssh-copy-id</tt>:</p>
<p><pre><code>$ ssh-copy-id babyspice.example.com</code></pre></p>
<p>And then you should be able to SSH to the remote host without being asked for a password! Great success.</p>
<p>Alternatively, find out what the key is so you can manually paste it into <tt>~/.ssh/authorized_keys</tt> on a remote host, or into
your GitHub profile, etc.:</p>
<p><pre><code>$ ssh-add -L</code></pre></p>
<p><b>Step 7</b>: So far, so good. The problem comes when you unplug the device and reinsert it. SSH just gives an error
"agent refused operation":</p>
<p><pre><code>$ ssh babyspice.example.com
sign_and_send_pubkey: signing failed for RSA "Public key for PIV Authentication" from agent: agent refused operation
jes@babyspice.example.com's password:</code></pre></p>
<p>It took me a little while to find out what was going on here because it wasn't mentioned in the YubiCo tutorial.
Eventually I found <a href="https://github.com/Yubico/yubico-piv-tool/issues/88">this GitHub issue</a>. The problem
is that the SSH agent does not reinitialise <tt>libykcs11</tt> when the YubiKey is plugged in (because it has no way
to know that it should), which means <tt>libykcs11</tt>
doesn't get a chance to ask you for the PIN, which means it can't unlock the YubiKey, which means it can't use it for SSH authentication.</p>
<p>This seems like a pretty big oversight, but fortunately it's quite easy to work around. All you need to do
is remove and re-add the keys provided by <tt>libykcs11</tt>. I added this to my <tt>~/.bashrc</tt> based on <a href="https://github.com/Yubico/yubico-piv-tool/issues/88#issuecomment-279102884">this
comment on the GitHub issue</a>:</p>
<p><pre><code>alias yf="ssh-add -e /usr/lib/x86_64-linux-gnu/libykcs11.so; ssh-add -s /usr/lib/x86_64-linux-gnu/libykcs11.so"</code></pre></p>
<p>Then whenever you plug in the YubiKey, you just need to run <tt>yf</tt> (for "YubiKey fix") before you'll be able to SSH anywhere. I suspect it
might be possible to trigger this automatically, but running it manually is adequate for now.</p>
<p><pre><code>$ yf
Card removed: /usr/lib/x86_64-linux-gnu/libykcs11.so
Enter passphrase for PKCS#11: 
Card added: /usr/lib/x86_64-linux-gnu/libykcs11.so</code></pre></p>
<p><h3>More</h3></p>
<p>I did this on Ubuntu 20.04 LTS. If you're doing it on a different system then the path to <tt>libykcs11.so</tt>
for example might be different. Also, Ubuntu seems to have YubiKey udev rules present out-of-the-box, and
automatically starts an <tt>ssh-agent</tt>, which you may have to sort out manually on other systems.</p>
<p>Sometimes when I plug the YubiKey in, instead of sitting there happily ready to work, the light flickers rapidly and
nothing shows up in <tt>dmesg</tt>. At first I thought I had bricked the device, but it seems like sometimes it
just doesn't work when you plug it in. I'm not sure if it sometimes gets a bad contact on the data pins, or if there
is a software problem on it. I just unplug it and plug it back in until the light stops flickering. I don't know
if this is just a problem with mine or they all do that.</p>
<p>We generated the key on the YubiKey itself, rather than generating it on the computer and sending it
to the key. This means there's no risk of leaving key material lying around anywhere it shouldn't be,
but it also means there is no way to make a backup of the key! If the YubiKey is lost or broken, you'll
have no way to use those keys for authentication. This means you need to have another way to gain access
to your machines for use in emergencies (for example, physical access to the machine, or a separate SSH
key that you keep safe, or password auth if nothing else). If you really want to import an existing key instead
of generating a new one, then see the <a href="https://developers.yubico.com/PIV/Guides/SSH_with_PIV_and_PKCS11.html">YubiCo
tutorial</a> and use <tt>import-key</tt> instead of <tt>generate</tt> in their Step 1.</p>
<p>I don't know what happens if you've unlocked your YubiKey to use SSH, and then someone comes across your locked PC with the unlocked YubiKey
inserted, attaches their own power supply to the USB connector, and then
unplugs the YubiKey without interrupting the power supply, and then plugs it into their own computer.
Will the YubiKey still be unlocked because it never lost power? Seems likely. You probably want to make sure to always unplug
the key every time you lose sight of it.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/yubikey.html</link>
   <guid>http://incoherency.co.uk/blog/stories/yubikey.html</guid>
   <pubDate>Fri, 01 May 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Automatic chess board design</title>
   <description><![CDATA[Lichess has recently released a Boards API, allowing anybody to
interface a physical chess board with lichess in order to play online games using an automatic board. I previously thought about implementing my Strange
Chess Clock using an automatic board, but never got round to it. With lichess now supporting online play with an automatic board, it's hard to justify not making one!]]></description>
   <content:encoded><![CDATA[<p><a href="https://lichess.org/">Lichess</a> has recently released a <a href="https://lichess.org/blog/XlRW5REAAB8AUJJ-/welcome-lichess-boards">Boards API</a>, allowing anybody to
interface a physical chess board with lichess in order to play online games using an automatic board. I previously thought about implementing my <a href="https://incoherency.co.uk/blog/stories/chess-clock.html">Strange
Chess Clock</a> using an automatic board, but never got round to it. With lichess now supporting online play with an automatic board, it's hard to justify not making one!</p>
<p><h2>Basic operation</h2></p>
<p>There are only 2 things an automatic chess board really needs to do. It needs to be able to move the pieces on the board, and it needs to be able to detect where the
player has moved the pieces on the board. You can view it as an input/output device: take input in the form of the player's moves, and provide output in the form
of the opponent's moves.</p>
<p>Complications can arise in certain designs, because in addition to basic piece moves, you need to be able to input and output:</p>
<p><ul>
<li>knight moves: knights are able to jump over other pieces, you need to account for this</li>
<li>captures: a piece gets removed from the board and the player's piece takes its place (in particular, if you only measure square occupancy, you might not know which piece was captured)</li>
<li>castling: the rook needs to jump over/around the king</li>
<li>pawn promotion: as input, you need to detect which type of piece the player promotes to; as output, you need to grab a captured piece and place it on the promotion square</li>
</ul></p>
<p><h2>Approaches</h2></p>
<p><h3>Mechanical Turk</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/2560"><img src="https://img.incoherency.co.uk/2560/thumb"></a></p>
<p>Hailing from 1770, the <a href="https://en.wikipedia.org/wiki/The_Turk">Mechanical Turk</a> was the world's first automated chess-playing machine. It actually
wasn't fully automated, there was just secretly a human inside who was providing the intelligence (an AI strategy that is still alive and well in Silicon Valley, I might add).</p>
<p>Each chess piece had a magnet in its base, and there was a corresponding magnet on a string underneath each square on the chess board. By observing which magnets
were attracted upwards to the underside of the board, the operator could tell which squares had pieces on. The operator had a small pegboard chess board inside the box,
on which he duplicated the game. Having decided on a move, he could move the Turk's arm using a <a href="https://en.wikipedia.org/wiki/Pantograph">pantograph</a>-type linkage,
and thereby move the pieces on the real board. This was accompanied by a fair amount of clanking and clockwork noises to make the illusion all the more convincing. I imagine it took
quite some skill to operate the Turk's arm without knocking all of the pieces over.</p>
<p><h3>Chess computers</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/2561"><img src="https://img.incoherency.co.uk/2561/thumb"></a></p>
<p>I have a chess computer (not pictured), it's quite a good way to play longer games at home. It's hard to find an opponent online to play a game that might last 4 hours, and even if you find one, it's easy
for one side or the other to get distracted or lose interest. A chess computer is a good way to sit down at a real board and play a long game of chess without distractions.</p>
<p>Typically you input your moves by pressing down on the piece you want to move, then moving it, and then pressing down on the square you moved it to. There is a membrane switch underneath
each square, which is what you're actuating by pressing the piece down. Once you've made a move, the computer thinks for a while and eventually beeps to alert you that it's decided on a move.
The LCD
display then tells you what it wants to move in a basic algebraic notation, e.g. mine says "E7E5" if it wants to move the piece from e7 to e5. You are then responsible for moving the
computer's piece, the same way you moved your own: press down on the square you're moving it from, then press down on the square you're moving it to.</p>
<p>This is quite good, but we ought to be able to detect the user's move without making him press down on the squares, we ought to be able
to apply the computer's move without making the user move the pieces, and it ought to be a bit hackable so that we can plug it into lichess for example instead of only being able
to play against the built-in AI.</p>
<p>If you're not familiar with chess computers, you might enjoy IM John Bartholomew's <a href="https://www.youtube.com/watch?v=b59-NaWOmtg">video about his Excalibur Explorer Deluxe chess computer</a>.</p>
<p><h3>Light-up squares</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/2571"><img src="https://img.incoherency.co.uk/2571/thumb"></a></p>
<p>An improvement over the basic chess computer is to put a light under each square. Instead of indicating its move by saying "E7E5", the computer simply lights up the square it wants you to move
a piece from, and then the square it wants you to move the piece to.</p>
<p>I've watched a demo of <a href="https://www.youtube.com/watch?v=f4WUa8H0cPo">quite a good DIY implementation</a>.</p>
<p><h3>Stepper motors</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/2565"><img src="https://img.incoherency.co.uk/2565/thumb"></a></p>
<p>If we want the computer to physically move the pieces itself, the most obvious way is to use a magnet to grab the pieces, and use stepper motors to move the magnet. You need a horizontal and vertical axis, and then you need some
way to grab the pieces from underneath using the magnet. One approach is to use an electromagnet which is switched on and off as required, and another approach is to use a permanent magnet
that is raised up and down with a solenoid, servo, or something else.</p>
<p>Most of the problems with this approach stem from the fact that you can only move the pieces in 2 axes. If a knight needs to jump over some other pieces, you need to figure out a way
to get it to its target square without moving it off the plane of the board. This normally means ensuring that the pieces are small enough to give sufficient space for the knight to move between the other pieces,
but in some cases it means moving other pieces out of the way first, or moving the knight through a more complicated route.</p>
<p>Stepper motors also tend to be quite noisy, which can rather disrupt the ambience of a quiet game of chess.</p>
<p>There are quite a few DIY projects on YouTube that implement this sort of mechanism, of varying standard and completeness level. One of the better ones is
<a href="https://www.youtube.com/watch?v=dX37LFv8jWY">Wireless Arduino Powered Chess</a> because it moves the pieces quickly, quietly, and in sensible routes.</p>
<p>There was actually a commercial board available in 1982, from Milton Bradley, and it seems to work quite well in <a href="https://www.youtube.com/watch?v=UxLd_wiGMA4">this video</a>. At 1:45
you can see it perform a knight move by first moving the pawn out of the way of the knight's path.</p>
<p><h3>Robotic arms</h3></p>
<p>Instead of using stepper motors underneath the board, you can use a robotic arm above the board that physically grabs and moves the pieces. This has the advantage that you can jump the knight
over the other pieces without issue, but comes with a risk of smacking the human if he doesn't get his hand out of the way fast enough, and also has potential reliability problems because
making a robotic hand that can consistently grip a chess piece is quite hard.</p>
<p>There's quite a good Instructable by <a href="https://github.com/NicholasMaselli">Nicholas Maselli</a> called <a href="https://www.instructables.com/id/Homemade-Chess-Robot/">Homemade Chess Robot</a> which uses a gripping hand:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2564"><img src="https://img.incoherency.co.uk/2564/thumb"></a></p>
<p>One of the more polished DIY robotic arm projects is <a href="https://www.raspberryturk.com/">Raspberry Turk</a>. Raspberry Turk solved the problem of the hand gripping the pieces by putting a small
steel rod in the top of each piece and using an electromagnet on the arm to grab the steel rod.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2568"><img src="https://img.incoherency.co.uk/2568/thumb"></a></p>
<p><h3>Magnet sensors</h3></p>
<p>In addition to moving the pieces, we also need the machine to detect which pieces the player has moved. An obvious way to do this is to put a magnet in each piece (which you potentially already
have if you're moving the pieces with stepper motors), and a hall effect sensor or reed switch under each square. You know what move the player made because you know what square a piece went missing from,
and you know what square a piece appeared in. Assuming no shenanigans on the part of the player (e.g. putting his pawn to one side and picking up a queen), you know that the square that
gained a piece got the same piece that was previously on the square that lost a piece.</p>
<p>This gets more complicated when a capture is made. When a piece is captured, one square loses a piece, but no square gains a piece, and in some positions the piece that moved has more than one
capture available, so the move is ambiguous. To get around this, you can continuously scan the
hall effect sensors for the presence of a piece so that you can notice the brief blip when the captured piece disappears before the capturing piece replaces it. In the event that this is
not detected, it will be up to the player to lift his piece up and put it back down to show which square it went to.</p>
<p>An alternative way to get around this problem would be to have (for example) North polarity at the bottom of the white pieces and South polarity at the bottom of the black pieces. You
can then tell which capture was made by noticing which square got its polarity reversed. If moving the pieces from underneath with an electromagnet, you would also need to be able to reverse the
current that is applied to the electromagnet, but this is doable.</p>
<p><h3>NFC, RFID, etc.</h3></p>
<p>To get an even better idea of which piece is on which square, you could equip each piece with a small NFC, RFID, or similar chip that identifies it. Then you need a sensor under each square which
has enough range to communicate with a piece directly above it but not enough to communicate with pieces on adjacent squares.</p>
<p><a href="http://www.digitalgametechnology.com/">DGT</a> manufacture a ~$600 chess board which can detect which pieces are on which squares, and these boards are commonly used at high-level
chess tournaments to provide real-time game data online. They look just like normal boards:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2563"><img src="https://img.incoherency.co.uk/2563/thumb"></a></p>
<p>I initially assumed that the DGT boards used NFC or RFID, but this <a href="http://chess.fortherapy.co.uk/home/chess-piece-identification-technology/">Chess Piece Identification Technology</a>
blog post includes this snippet from the now-defunct "chessprogramming.wikispaces.com":</p>
<p><blockquote>The patent-registered DGT sensor technology recognizes pieces containing piece-type and piece-color specific passive LC circuits with a resonance frequency of 90 to 350 KHz, the coil on ferrite core. Squares and their respective pieces (if any) are scanned by 2 x 8 silver-ink printed trace loops on a polyester film placed under the board, file and rank sequentially selected by analogue switch multiplexers, feeding back the output signal of an amplifier via the selected inductive coupled LC circuit to its input, forcing oscillation in piece specific resonance. Measuring the signal frequency or its period via a digital input port by the controller firmware to convert it into appropriate piece codes takes about 3 ms per square.</blockquote></p>
<p>Which is a really interesting way to do it, and makes complete sense given the limited number of piece types and colours that must be identified. It even seems like it should be possible to make
a really thin (like, 3 sheets of paper) panel that can be placed underneath ordinary standard-sized chess boards to provide the same effect, and then it would "just" be a case of making compatible coils and sticking them in some
chess pieces, and a controller that constantly scans the squares, and you've duplicated the DGT product for substantially cheaper. That might be a fun project on its own.</p>
<p>It's not obvious to me, from reading that quote, whether there are 2 frequencies that identify the colour and 8 that identify the type, and therefore each piece needs 2 coils, or whether
there is 1 frequency that identifies a colour and type, and therefore each piece has only 1 coil. Seems like either way would work, and putting only 1 coil in each piece would be easier and
cheaper. It does mean you need to scan each square for 16 different frequencies instead of only 10, but I can't see that being a problem.</p>
<p><h3>Computer vision</h3></p>
<p>Computer Vision is relatively accessible these days, so just pointing a camera at the board and training a neural net on it is a perfectly viable solution. Raspberry Turk
works this way (although the computer vision there is relatively minimal - most of the time it is only testing for which colour is on each square, and inferring what piece is there based
on what it already knows about the position), and Daniel Bowers has a great blog post on <a href="http://danielbowers.com/robot-chess-computer-vision/">Robot
Arm, Chess Computer Vision</a>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2566"><img src="https://img.incoherency.co.uk/2566/thumb"></a></p>
<p><h3>SquareOff</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/2567"><img src="https://img.incoherency.co.uk/2567/thumb"></a></p>
<p><a href="https://squareoffnow.com/">SquareOff</a> is a commercial implementation of the stepper motor/magnet sensor solution. The base model costs $390 and it looks very promising,
except it's not very hackable (e.g. you can't use it to play on lichess) and it requires the use of a proprietary smartphone app. Such a shame, because it seems to work well.
If they'd let us control it with a USB serial port instead of a phone I'd have considered buying one.</p>
<p><h3>Regium</h3></p>
<p>Regium was a KickStarter project launched this year (and now <a href="https://www.chess.com/news/view/update-on-regium-chess">suspended</a> for being <a href="https://lichess.org/blog/XlE48hEAACIAQv2F/regium-extraordinary-claims-require-extraordinary-evidence">an obvious scam</a>). It purported to use
a high-density grid of tiny electromagnets underneath the board surface to move the pieces.</p>
<p>If it existed and worked, this could actually meet many of the claims made by the Regium KickStarter campaign: you could use the electromagnets to lock the pieces in position for transport, to move multiple pieces simultaneously, to move the pieces quickly and silently, etc. In fact, using stepper motors to move an electromagnet around is just a really low-fidelity way to manipulate the magnetic field underneath the board. Comparing it to visible light, if the stepper motors are waving around a light on a stick, the Regium board is an LCD panel.</p>
<p>Unfortunately, it doesn't exist and it doesn't work, and the product demo videos were faked. It is a great idea though and I'd be really interested to see if anybody could actually make it work.</p>
<p><h2>My design</h2></p>
<p>I'm using stepper motors to move an electromagnet, with magnets on the bottoms of the pieces, and hall effect sensors under the squares to sense the pieces. I designed the mechanical
parts in <a href="https://freecadweb.org/">FreeCAD</a> and put them together using the <a href="https://github.com/kbwbe/A2plus">A2plus</a> workbench.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2556"><img src="https://img.incoherency.co.uk/2556/thumb"></a></p>
<p>(The reason the case in the model is rectangular is because I was originally planning to have a control panel to one side of the board, but I'm now planning to have it as a separate unit on an
umbilical cord so that it can be rotated to face either the black side or the white side of the board).</p>
<p>This was my first time using the A2plus
workbench and initially I liked how easy it was to define constraints between the parts. Unfortunately I found that if I changed any of the parts in any way, then when I updated the
part in the assembly, A2plus had lost track of which pieces of geometry were supposed to be constrained. This is very annoying and means you need to redefine the constraints for a part every
time you change the part. I read somewhere that A2plus is best used when you have already committed to the design of the parts and you just want to assemble them together, but that is
not really a useful workflow. If I've already committed to the design of the parts, I can just print them out and assemble them together in real life! The point of the assembly workbench
is that I can design the parts around each other in an iterative way until I'm happy with how they fit together. So I'm on the lookout for a better assembly workbench. I've read that Assembly4
solves this particular problem because it defines the constraints between parts relative to their local coordinate systems instead of relative to particular pieces of geometry, although I
couldn't quite understand the Assembly4 UI so I haven't got far enough to try it out yet.</p>
<p>I 3D printed the parts in 3DXTech's <a href="https://www.3dxtech.com/carbonx-nylon-cf/">CarbonX Nylon+CF</a>, this is a nylon-based filament reinforced with carbon fibre to increase
its stiffness. For these particular parts, ordinary PLA would have been more than sufficient, but it's always cool to use carbon fibre.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2555"><img src="https://img.incoherency.co.uk/2555/thumb"></a></p>
<p>I'm planning to deal with knight moves by allowing enough space for the knight to move between pawns, and in the case of larger pieces in the way, by moving one of the other pieces out of the way first, like
on the Milton Bradley board. I'm planning to handle castling and captures by allowing the stepper motors to access the centres of the squares of a "virtual" 10x10 board, providing access to 1
extra square along each edge of the board. The rook can move through this virtual square to pass to the other side of the king, and captured pieces can be placed on a virtual square. When
the player promotes a pawn, I'll have the UI on the control panel ask what piece he promoted to, and when the opponent promotes a pawn, I'll have the UI on the control panel instruct the
player to place the appropriate piece on the promotion square.</p>
<p><h3>Electronics</h3></p>
<p>For the electronics, I'm using a <a href="https://www.pjrc.com/store/teensy32.html">Teensy 3.2</a> for the microcontroller. It's basically the same as an Arduino Nano except a bit smaller,
with more pins available, more memory, and more CPU power. To drive the stepper motors I'm using 2x A4988 breakout boards salvaged from my <a href="https://incoherency.co.uk/blog/stories/3d-printer.html">old 3d printer</a>,
which is also where I got the stepper motors and the linear bearings from. I'm using analogue hall effect sensors instead of digital ones, just in case it ever becomes useful to detect a piece
that isn't quite centred, for example. To read the signals from the 64 hall sensors I'm using 8x CD4051 8-to-1 analogue multiplexers. I'm using a cheap no-name eBay electromagnet to grab the
pieces, and driving it using an IRF520 MOSFET.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2569"><img src="https://img.incoherency.co.uk/2569/thumb"></a></p>
<p>I've included provision for a jumper to bridge the motor voltage and the electromagnet voltage together. I expect that both of these will run on 12v, but if I ever want to change the
voltage of one of the parts, I can easily remove the jumper and supply a different voltage. I've also included provision for 3 jumpers next to each of the stepper drivers, this is
so that I can change the microstepping mode. For maximum speed I expect I will be running with microstepping disabled, but it is possible that whatever speed I settle on will be
attainable with some mcirostepping enabled, and that should quieten the motors down a bit.</p>
<p>I designed the PCB in <a href="https://www.kicad.org/">KiCad</a>, and <a href="https://www.pcbway.com/">PCBWay</a> have generously agreed to manufacture it for me for free, so expect
some commentary on the PCBWay board soon.</p>
<p><h3>Mechanics</h3></p>
<p>I mounted the mechanical parts inside a plywood frame, and made the top of the board out of 6mm MDF.</p>
<p>The top needs to be as thin as possible in order to help the electromagnet grab hold of the pieces. But I also don't want it to be too flexible. Several other projects I've seen have used
a glass top because glass is thin and stiff, but it seems a bit fragile for my taste. I considered using a sheet of some sort of plastic, but MDF is more convenient. Normally I prefer making
things out of plywood than MDF because it is stronger and MDF doesn't hold screw threads very well, but I have found plywood at this sort of thickness to be quite poor quality,
and since I don't need the top to hold any screw threads anyway, MDF will suffice.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2570"><img src="https://img.incoherency.co.uk/2570/thumb"></a></p>
<p>(The board is upside down in that photograph. The intersections of the grid are the centre points of the squares on the virtual 10x10 board, and you can see there is a hall effect
sensor superglued under the centres of the central 8x8 squares).</p>
<p>The linear bearings are a little bit on the... crunchy side. I have certainly lost at least one of the tiny ball bearings from inside while fitting the rods, and it's possible a few others
have escaped without me noticing. On a few occasions I have observed the bearings bind up while trying to move them quickly, so I might have to replace them at some point.</p>
<p>If you've worked with stepper motors before you might notice a glaring omission in my design: there are no limit switches! That means when the machine wakes up from a cold boot, it has
no idea what position the electromagnet is at relative to the chess board. I watched a video <a href="https://www.youtube.com/watch?v=EHRc-QMoUE4">How Old School Floppy Drives Worked</a>
by The 8-Bit Guy a while ago, and learnt that some older floppy drives homed their stepper motors by simply driving them to one end of the axis for long enough that it has definitely reached
the end. The head will crash into the end at some point and stop moving, resulting in an unnerving grinding noise as the motor tries to drive it further. But this does no harm to the stepper
motor, and as long as the mechanical assembly is strong enough to handle it, no harm is done at all. I thought this was a very funny solution so I intend to use it in the chess board.
In the absence of a proper name, I think I'll refer to it as "crash homing". In the case of my chess board, it might also be possible to detect the position of the electromagnet by switching
it on and wiggling it around and trying to find it using the hall effect sensors, so maybe that could be the primary method, and crash homing is just a last resort.</p>
<p><h3>Software</h3></p>
<p>I initially wanted to use the <a href="http://www.airspayce.com/mikem/arduino/AccelStepper/">AccelStepper</a> library to control the stepper motors. It allows you to specify a maximum
acceleration and maximum velocity for your motors, and then move them to target positions within these constraints. It also includes a "MultiStepper" class that can control more than
one stepper motor at a time in order to move in a straight line to a new target position. Unfortunately, the MultiStepper class does not implement acceleration, so you have to decide
whether you want to control the axes independently, but with acceleration, or whether you want to coordinate the 2 axes, but only move at a constant speed. I want to coordinate my 2 axes
and move them both with smooth acceleration, so I think I'm going to have to implement that myself.</p>
<p>Many of the stepper motor chess boards seem to do a very poor job of routing the pieces along the board surface, which makes them move very strangely. For example, in one project I observed a bishop move
in a path like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2562"><img src="https://img.incoherency.co.uk/2562/thumb"></a></p>
<p>It is obvious why this has happened: the machine is programmed to first move the piece to the corner of its square (with big enough squares, moving along the edges of squares ensures you can never crash
into other pieces), then move 
in the horizontal direction, then the vertical direction, and then finally move to the centre of the square. This is surprisingly common in many of the
YouTube demonstrations, so part of me wonders if they're all university coursework for the same course, and the professor has advised that they implement movement this way.
But in my opinion this can be improved so that the pieces move more naturally without too much programming difficulty, so I intend to do so.</p>
<p>So far I've got as far as moving a single bishop back and forth on top of the board, and you can <a href="https://www.youtube.com/watch?v=8_zU5RWM38c">see a demonstration of that</a> if you want.</p>
<p><h3>Trouble with magnets</h3></p>
<p>I already had a magnetic chess board, so I was hoping to be able to use the pieces from that set on the automatic board. It turns out that the magnets in those pieces are much too weak. I have
removed all of the original magnets and replaced them with neodymium equivalents, and the electromagnet is now able to grab hold of the pieces and slide them around the surface of the board.</p>
<p>Unfortunately, when pieces get too close together, they repel each other because of the strength of the magnets in their bases. It would work fine for most pieces because they don't need to get
close to each other, but when the knight tries to move between 2 other pieces, it pushes each one away. I really need to find a magnet solution that is strong enough for the electromagnet
to grab it, but weak enough not to repel adjacent pieces. If you have any thoughts on this I'm interested in hearing them. In case it helps: I have 48mm squares, which means when the knight moves
between two pieces the centres of the magnets will be 24mm apart. I have 12mm holes in the base of most pieces and 10mm in the pawns, and I have 4mm depth available. There is 11mm between
the top of the electromagnet and the bottom of the chess piece, 6mm of which is the MDF board, and 5mm is clearance for the hall effect sensors although this could probably be reduced slightly
once I've wired it all up.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/automatic-chess-board-design.html</link>
   <guid>http://incoherency.co.uk/blog/stories/automatic-chess-board-design.html</guid>
   <pubDate>Sat, 14 Mar 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>My first combat robot tournament</title>
   <description><![CDATA[At the weekend, I took Wedge of Glory to an antweight combat robot tournament in Hinckley called Ant Freeze 7.]]></description>
   <content:encoded><![CDATA[<p>At the weekend, I took <a href="https://incoherency.co.uk/blog/stories/wedge-of-glory.html">Wedge of Glory</a> to an antweight combat robot tournament in Hinckley called <a href="http://antlog.garya.org.uk/event/24">Ant Freeze 7</a>.</p>
<p><h2>Hinckley</h2></p>
<p>While in Hinckley we visited <a href="https://twycrosszoo.org/">Twycross Zoo</a> and the <a href="https://www.triumphmotorcycles.co.uk/visitor-experience">Triumph Factory Visitor Experience</a>.
The Triumph factory tour was excellent. Compared to the Toyota tour that I've done before, the Triumph factory is less impressive, but
the tour is much more detailed and you actually walk around the factory floor instead of a raised walkway. They show you parts storage, machining stations,
a CNC measurement room, the paint shop, engine assembly line and motorcycle assembly line. Really interesting, I highly recommend it.</p>
<p><h2>Ant Freeze</h2></p>
<p>We arrived at the tournament venue at about 9.15am on the Saturday morning. The first order of the day is to get the robot checked,
and pay the entry fee of &pound;2. The robot must fit inside a cube of 4 inches on each side, and weigh no more than 150 grams. My robot weighed
in at 151 grams. This was accepted, however.
A last-minute modification I had made was to add insulating tape around the edges of the robot to cover up the join between the chassis halves, just
to remove them as a potential grabbing point. This is probably what pushed the weight up.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2534"><img src="https://img.incoherency.co.uk/2534/thumb"></a></p>
<p>The other issue was that I couldn't get the robot to fit inside the cube without squashing it, even though we know from the CAD model that it should fit,
and the play in the hinge should make it fit in real life more easily than in CAD:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2495"><img src="https://img.incoherency.co.uk/2495/thumb"></a></p>
<p>I am suspicious that the cube they were testing with was ever so slightly under-size (e.g. 100mm instead of 4 inches). In any event, it was deemed close
enough to be acceptable, and I didn't have to make any modifications.</p>
<p>Some people bring more than one robot, and these are grouped into "teams", with a limit of 3 robots per team. The fight scheduling algorithm assigns the teams
with 3 robots to groups first (so that they don't have to fight themselves during the group stages), followed by the teams with 2 robots,
followed by the teams with only 1 robot. This meant I was one of the last robots assigned to
a group, and it also happened that my group had an odd number of robots, which meant I was given a bye in round 1. In total there were 111 robots entered.
 The result of all this is that my first
fight wasn't until 1.30pm. It seems a bit unfair that some people could conceivably have 6 fights before others
have even had their first, but that's the way it is.</p>
<p>The tournament format is called "double elimination". It's a bit like a normal tournament bracket with a group stage, except you're not knocked out
until you've lost 2 fights.</p>
<p><h2>Fights</h2></p>
<p>Emma filmed all of my fights, so if you want, you can watch <a href="https://www.youtube.com/watch?v=3NQXdhqR2CE">a video of Wedge of Glory at Ant Freeze 7</a>.</p>
<p>The first fight was against a robot called Stubble. As far as I can tell, this is also a 4-wheel-drive wedge. It almost managed to push me into the pit, but I escaped
and circled round and managed to push Stubble into the pit instead. I was very pleased to win my first fight as I was concerned that I wasn't good enough at driving
it.</p>
<p>I've forgotten the name of the robot that the second fight was against, but it is a 2-wheel-drive flipper with a TinkerCAD logo on the flipper. More through luck
than judgment, I just drove straight forwards, managed to get the wedge underneath the front of the other robot, and then drove it straight into the pit. I was
beginning to think I might be quite good at this.</p>
<p>The third fight was against a "cluster" called Wedge Wedge Wedge. This consists of three 2-wheel-drive wedges. It's hard to know which one to aim for, and I
think I managed to confuse myself and quickly drove my own robot into the pit. A combination of stupidity and inexperience, I think.</p>
<p>Next I was up against a robot called "Jammin' Good with Weird and Flippy" which is a 2-wheel-drive flipper with a steel front on it. Luke, the operator of this robot,
seemed quite confident that his flipper was closer to the ground than my wedge and therefore I wouldn't be able to get underneath him. It turned out the opposite
was true, and Wedge of Glory quite comfortably drove underneath Jammin' several times, before eventually leaving it on the edge of the pit, where it fell in on
its own. Winning this fight meant I reached the final 16 which was quite exciting!</p>
<p>My final fight was against a robot called CATanix which seems to be a 2-wheel-drive wedge. It looks like they swap out the nature of the wedge on the front
based on what type of robot they're fighting, which seems like a good idea. I was thoroughly out-driven in this fight. CATanix quickly manouevred around to
the side of Wedge of Glory, and got the wedgelets underneath. I was desperately trying to wriggle free but I think all of the wheels were off the ground, and I had
no control. I was eventually dumped into the pit, and knocked out from the tournament.</p>
<p>After the main tournament was over, there was a "Gladiator" fight in which anybody who wants to participate can chuck a robot in the arena all at once.
There were about 30 entries, and it was chaos. I got flipped upside down a couple of times, which was my first opportunity to
use the controller inverting switch, which worked but wasn't as easy to reach as it could have been. I eventually managed to
drive myself on top of a pile of robots stuck in a pit and was unable to drive off again, so that was the end for me.</p>
<p>The "Gladiator" was the only fight in which Wedge of Glory sustained any damage, and even watching the video back I can't really
tell what happened. It looks like something took a small bite into the end of the wedge and ripped off some of the plastic:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2533"><img src="https://img.incoherency.co.uk/2533/thumb"></a></p>
<p>I would have liked to have had a 1-on-1 fight against a spinner, as I still don't know what would happen. Most of Wedge of Glory is printed with quite low
infill and only 1 perimeter in order to save on weight, so it's quite possible that a spinning weapon would easily pierce it.</p>
<p><h2>Robot design</h2></p>
<p>I received a few compliments on the quality of the engineering in Wedge of Glory, which I didn't expect. I think possibly this is because I used less hot glue
and blu-tack than many of the other competitors.</p>
<p>At the start of the first fight, the robot stopped responding to my inputs properly as soon as I shut the lid on the arena. I opened it back up
and switched the robot off and on again and then it was fine. The same thing happened at the start of the second fight, but it was fine for the others. I don't know
what was going wrong.</p>
<p>The receiver used in Wedge of Glory is a FlySky FS-iA6. It's the standard one that is delivered with the controller and weighs about 9 grams. I subsequently learnt
that most people are using alternative receivers that weigh less than 1 gram! Switching to one of those would free up quite a lot of mass that could be added to
the thickness of the 3D-printed parts.</p>
<p>In order to charge Wedge of Glory's battery, I need to remove all of the insulating tape around the edge, and undo the 4 screws that hold the chassis halves together,
to gain access to the charging plug. This is annoying and time-consuming, and reassembly is fiddly. An improvement would be to make a hole next to the power
switch through which the charging plug can be accessed, so that the battery can be charged without having to disassemble the robot.</p>
<p>The main design flaw that I discovered was that Wedge of Glory is very vulnerable to other wedges lifting it up from the side. This is how I lost the fight
against CATanix. Possibly it would help if the wheels
were moved outwards, closer to the outside edges, so that when the robot is tipped up slightly it still has wheels on the ground and can potentially
free itself.</p>
<p>I'm planning to build at least 1 more robot for the next competition, and possibly 2. One idea is I'd like to clone Robert Cowan's
<a href="https://www.youtube.com/watch?v=RBld2zpbvxg">Kamikaze</a> robot, but in the antweight class. This has a large spinning weapon that traces out a path
around the entire perimeter of the robot so that nothing can contact the robot without getting hit by the weapon.</p>
<p>Another idea is to have a large "skip" that unfolds
at the start of the fight big enough to fit other robots inside, and with a ramp at the front. Once the other robot is inside the skip, the ramp at the
front would be brought up to form another wall on the skip so that the other robot is trapped inside. Then you just drive over to the nearest pit and empty
the skip into it. It would be quite challenging to actually make this, but it would be cool if it works.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/antfreeze.html</link>
   <guid>http://incoherency.co.uk/blog/stories/antfreeze.html</guid>
   <pubDate>Mon, 03 Feb 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I built an antweight combat robot</title>
   <description><![CDATA[If you've ever seen Robot Wars or BattleBots,
you'll know what a combat robot is. An antweight combat robot is the same concept, except it has to weigh no more than 150g and fit inside a 4-inch cube. I've
built one, called "Wedge of Glory", and have my first competition this weekend!]]></description>
   <content:encoded><![CDATA[<p>If you've ever seen <a href="https://en.wikipedia.org/wiki/Robot_Wars_(TV_series)">Robot Wars</a> or <a href="https://en.wikipedia.org/wiki/BattleBots">BattleBots</a>,
you'll know what a combat robot is. An <b>antweight</b> combat robot is the same concept, except it has to weigh no more than 150g and fit inside a 4-inch cube. I've
built one, called "Wedge of Glory", and have my first competition this weekend!</p>
<p><a class="img" href="https://img.incoherency.co.uk/2532"><img src="https://img.incoherency.co.uk/2532/thumb"></a></p>
<p>I also have <a href="https://www.youtube.com/watch?v=0_t4P_eA-ds">a video demonstration</a>, from before I painted the logo.</p>
<p>I kept a <a href="http://robotwars101.org/forum/viewtopic.php?f=1&t=2954">progress log as I went along</a> on the RobotWars101 Forum, which turned out to be quite
helpful as I received good feedback and ideas from other forum members.</p>
<p><h2>Design</h2></p>
<p>I watched quite a lot of antweight fights on YouTube (e.g. <a href="https://www.youtube.com/watch?v=Yd6b21LqA3M">Antweight World Series 60</a>) and noticed
that a lot of the time, the robots that have big spinning weapons do more harm to themselves than to their opponents. They tend to get maybe one decent hit,
and then start <a href="https://battlebots.fandom.com/wiki/Gyro_Dance">gyrodancing</a>, bounce around the arena, and either self-destruct or bounce into the pit. So
for a first robot, a big spinning weapon is definitely not the way to go.</p>
<p>I observed a few other silly ways of losing a fight, such as some robots driving themselves into the pit, and some becoming immobilised due to being upside down. It seems obvious that
every robot should either be able to self-right, or even better, work upside down.</p>
<p>So we want a robot that doesn't have a big spinning weapon, has good control so as not to accidentally drive into the pit, and has the ability to recover if flipped
upside down. For these reasons I designed a 4-wheel-drive skid-steer pushing robot that works identically when upside down. The idea is that it wins fights by pushing the other
robot into the pit. Here's the CAD of the first iteration:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2490"><img src="https://img.incoherency.co.uk/2490/thumb"></a></p>
<p>The wedge at the front is free to pivot so that when the robot is upside down it still sits on the ground. There is complete protection of the wheels on all sides.
The chassis is made of 2 of these identical halves, which clamp the gear motors in place without any additional motor mounts, and the rest of the electronics just
sit in the cavity in the middle.</p>
<p>Here it is printed in PETG to test the fit:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2491"><img src="https://img.incoherency.co.uk/2491/thumb"></a></p>
<p><h2>Electronics</h2></p>
<p>I've never done any radio-control electronics before, so I wasn't entirely sure what to buy. I ended up getting a "FlySky FS-i6" transmitter and receiver,
a dual ESC from <a href="https://bristolbotbuilders.com/">Bristol Bot Builders</a>, a 180mAh Turnigy "nano-tech" LiPo battery, and 6v 300rpm "N20" gear motors.</p>
<p>In the picture above, the motors look like the ordinary motors you play with at school, but they are actually only 12mm in diameter.</p>
<p>All of the wiring has silicone insulation. This seems to be common in RC applications, and both the battery and ESC came with silicone wires already fitted.
Unfortunately the battery connector on the ESC was not the same as on the battery, so I cut it off and replaced it with a match for the battery one. It's known
as a "Losi Micro" or "Walkera" 2-pin connector. The most convenient way I could purchase these was as loose connectors and pins that you have to crimp onto wires
yourself. I've tried to crimp ordinary 2.54mm JST connectors before and have literally never succeeded, and these are even smaller, so this time I
cut the crimping part of the pins off and soldered the wires on instead, and then pushed the soldered pins into the connector housing.
This worked much better, and I recommend it. It is true that in theory you
can get a stronger connection by crimping because then the insulation is held in addition to the conductor. But in practice, an average solder joint is stronger
than an average DIY crimp attempt.</p>
<p>The receiver is designed to have 3-pin servo plugs connect to it, but these take up quite a lot of space and weight,
so I trimmed the pins down and soldered wires directly. The receiver, battery, and ESC are then cable-tied together into a single package that sits in the centre
of the robot. It's a 2.4GHz receiver using a digital mode, which means you have to pair the receiver to the transmitter. This is new to me, last time
I had any RC toys they were "paired" by physically switching crystals around, and you had to ensure that you didn't use the same frequency as anyone else
in the immediate vicinity. The digital mode seems to be a great improvement.</p>
<p><h2>Taulman 910</h2></p>
<p>I bought a spool of Taulman Nylon "Alloy 910" <a href="https://shop.3dfilaprint.com/alloy-910-black-175mm-1lbs-3d-printer-filament-12567-p.asp">from 3dfilaprint</a>.
This is a very strong and slightly flexible nylon filament designed for engineering applications. There is a video of a man <a href="https://vimeo.com/380594304">splitting a block of wood apart</a> with a chisel printed in Taulman 910, and I have also reproduced this result. Quite impressive stuff. (Admittedly, I haven't tried it
with PLA or PETG, so maybe that would work too, but I expect the PLA would just shatter when you hit it with the hammer).</p>
<p>I wasn't sure whether I'd be able to print it
or not, but I still had PETG as a fallback, and it turns out that Taulman 910 prints very nicely. I hope to use it a lot more.</p>
<p>I am printing it on an Anycubic i3 Mega, which has an "Ultrabase" build plate. It sticks well with the bed at 45&deg;C, which is how I use it, but it doesn't release very easily after the print is done. That's a tradeoff I'm happy with, particularly in consideration of the fact that nylon is very
prone to warping during printing if it is not stuck to the bed well enough. I initially tried it with the bed hotter and it kept peeling up and warping.</p>
<p>Taulman suggest printing it at 250-255&deg;C. I'm printing it at 245&deg;C and it seems fine. Perhaps layer adhesion would be better at higher temperatures, but
overhang performance is worse.</p>
<p>It is of utmost importance that nylon filament is dry. It wicks moisture out of the air, which causes reduced strength and poor print quality. It can be dried by leaving
it in the oven overnight at 80&deg;C, and I found that it degrades significantly after less than a day exposed to the air. For this reason I have created
a small <a href="https://www.instructables.com/id/3D-Printer-Filament-Dry-Box/">drybox</a> which allows me to print the filament without exposing it
to a moist atmosphere:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2528"><img src="https://img.incoherency.co.uk/2528/thumb"></a></p>
<p>It's just a food storage box with a spool-holding spindle and a PTFE tube running to the printer for the filament to go down. Currently I just have a packet
of silica gel in there, but I have ordered some loose silica gel beads that change colour when they
can no longer absorb moisture, which I'll leave loose in the bottom.</p>
<p>Unfortunately most of the robot parts were printed before I had made the drybox, here's a comparison between dry filament (left) and moist-ish filament (right)
both printed with identical GCode:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2530"><img src="https://img.incoherency.co.uk/2530/thumb"></a></p>
<p>In addition to improved print quality, the part printed with dry filament is noticeably stiffer.</p>
<p><h2>Wheels</h2></p>
<p>The first suggestion I got was to remove the wheel protection from the back of the robot so that if the front of the robot gets lifted up, it still has some grip
from the rear wheels. This is a great idea, and also reduces the amount of space and weight taken up by the chassis.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2493"><img src="https://img.incoherency.co.uk/2493/thumb"></a></p>
<p>A pushing robot lives and dies by its pushing ability, so I wanted some nice grippy wheels. I bought some 2-part liquid silicone rubber off eBay, and 3d printed
wheel hubs and tyre moulds. The hubs have holes running through them so that the silicone is mechanically attached to the wheel, to prevent the tyre from falling
off.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2506"><img src="https://img.incoherency.co.uk/2506/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2507"><img src="https://img.incoherency.co.uk/2507/thumb"></a></p>
<p>With the hub placed inside the mould, silicone is poured in and allowed to cure, at which time the mould is removed and you just have to clean up the flashing and
you're left with a nuce grippy tyre moulded on to the hub. I did a test piece with a smooth tyre first:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2499"><img src="https://img.incoherency.co.uk/2499/thumb"></a></p>
<p>I found that in liquid form, despite its apparent viscosity, the silicone was able to seep through the cracks in the mould and I lost quite a bit of it.
For the real tyres, I sealed up the mould with hot glue before pouring the silicone, and also made sure to pour plenty:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2500"><img src="https://img.incoherency.co.uk/2500/thumb"></a></p>
<p>This did the trick, and I got 4 nice grippy tyres. The clamps are there to prevent the hub from floating, as the (mostly hollow) hubs are less dense than the silicone.</p>
<p><h2>Wedge</h2></p>
<p>The initial wedge design came with a risk of other robots driving straight over the top, which is not what we want. To solve this,
I cut a step into the wedge so that once it has lifted the other robot off its wheels, it has half a chance of catching it and pushing
it along.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2494"><img src="https://img.incoherency.co.uk/2494/thumb"></a></p>
<p>All installed on the robot, we get this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2505"><img src="https://img.incoherency.co.uk/2505/thumb"></a></p>
<p>Although I wasn't very happy with the surface finish on the underside of the wedge. To solve this, I printed it pointing straight upwards (right)
instead of lying flat (left), so that the step doesn't create an unsightly overhang:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2529"><img src="https://img.incoherency.co.uk/2529/thumb"></a></p>
<p>There was some concern on the forum that the wedge wasn't sharp enough to go under other robots, but I think it's fine:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2508"><img src="https://img.incoherency.co.uk/2508/thumb"></a></p>
<p><h2>4-inch cube</h2></p>
<p>The 4-inch cube rule states that the robot must fit inside a 4-inch cube in any orientation. It needn't have its wheels touching the floor while in the cube,
but it is not allowed to fit in the cube merely by virtue of being folded up, or springy. It has to fit in the same shape as that in which it will
begin the fight, although it is fine to unfold later as long as this is initiated after the fight starts. For example, a flipper robot doesn't need its full flipper
motion constrained by the dimensions of the cube.</p>
<p>My robot fits precisely across the diagonal of the 4-inch cube:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2495"><img src="https://img.incoherency.co.uk/2495/thumb"></a></p>
<p><h2>Controller</h2></p>
<p>When the robot is upside down, steering still works correctly. When you steer, the left and right wheels spin in opposite directions. With the robot upside down,
the wheels have moved to the opposite side, and are spinning in the opposite direction. These effects cancel out and steering still works, but forwards and
backwards movement become inverted. To fix this I wanted to use one of the auxiliary switches on the controller to invert the "throttle" input so
that if the robot is upside down I could simply flick the switch and continue driving as normal.</p>
<p>Despite the wealth of configuration options available in the FS-i6 menu, it appears that it is actually impossible to get it to invert a channel at the flick of a
switch. It has a way to permanently invert a channel, and it has a way to use a switch to set a different rate on a channel, but it has no way to let you select
a negative rate. Razerdave on the forum suggested a solution.</p>
<p>Each input axis controls one potentiometer. By cutting the connections to the potentiometer and inserting a DPDT switch in the middle,
we can invert the voltages at the ends of the axis so that the transmitter thinks we've moved the joystick in the opposite direction.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2502"><img src="https://img.incoherency.co.uk/2502/thumb"></a></p>
<p>I did this by opening the controller up, finding the potentiometer that I am interested in, cutting the pins for the two ends of the potentiometer, and soldering
wires in their place. By twisting the wires together first the same way as before, and then inverted, I verified that this correctly inverted the operation
of the joystick. Great success!</p>
<p><a class="img" href="https://img.incoherency.co.uk/2504"><img src="https://img.incoherency.co.uk/2504/thumb"></a></p>
<p>I then drilled a hole in the case and fitted a DPDT switch to the ends of the wires:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2510"><img src="https://img.incoherency.co.uk/2510/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2509"><img src="https://img.incoherency.co.uk/2509/thumb"></a></p>
<p>Quite a neat mod, I think.</p>
<p>The only surprise was that the centre position of the joystick does not exactly correspond with the centre position of the potentiometer, but usually you wouldn't
notice because this is compensated in software so that the channel is at the 0 position with the joystick centred. Unfortunately, when you invert the joystick, the centre position is no longer the 0 position. I have worked around this by setting the trim on the channel so that it's close to the centre in both the forwards
and reverse mode, and in both cases the error remains within the hysteresis on the ESC so the robot stays still with the stick centred.</p>
<p><h2>Logo</h2></p>
<p>To finish the robot off, and to help me distinguish the top from the bottom, I 3d printed a stencil and spraypainted a "Wedge of Glory" logo
on to one side of the chassis:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2531"><img src="https://img.incoherency.co.uk/2531/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/wedge-of-glory.html</link>
   <guid>http://incoherency.co.uk/blog/stories/wedge-of-glory.html</guid>
   <pubDate>Mon, 27 Jan 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>My DIY Cryptosteel Capsule</title>
   <description><![CDATA[Bitcoin wallets give you a mnemonic seed to write down and keep safe. This is usually 12 to 24 words
from the BIP39 word list. But if you write it on paper, it is easily
damaged by flood or fire. An improvement is "Cryptosteel"-type devices, which allow you to record the mnemonic seed in metal, such that it is
recoverable in the event of flood or fire. I built one myself.]]></description>
   <content:encoded><![CDATA[<p>Bitcoin wallets give you a <a href="https://en.bitcoin.it/wiki/Seed_phrase">mnemonic seed</a> to write down and keep safe. This is usually 12 to 24 words
from the <a href="https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt">BIP39 word list</a>. But if you write it on paper, it is easily
damaged by flood or fire. An improvement is "Cryptosteel"-type devices, which allow you to record the mnemonic seed in metal, such that it is
recoverable in the event of flood or fire. I built one myself.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2523"><img src="https://img.incoherency.co.uk/2523/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2522"><img src="https://img.incoherency.co.uk/2522/thumb"></a></p>
<p><b>Update 2022-08-02:</b> If you want to make yourself a capsule
but don't have the use of a lathe, you can follow the instructions
on (a Wayback Machine archive of) <a href="https://web.archive.org/web/20230123000631/https://safu.ninja/">safu.ninja</a>.</p>
<p><h2>Metal seed storage</h2></p>
<p><a href="https://www.lopp.net/">Jameson Lopp</a> writes an interesting series on <a href="https://jlopp.github.io/metal-bitcoin-storage-reviews/">Metal Bitcoin Seed Storage Reviews</a> in which
he (sometimes destructively) tests various metal seed storage products with water, fire, acid, and a hydraulic press, and reports on how well they perform.</p>
<p>Most of the metal key storage devices work like this (the original Cryptosteel product):</p>
<p><a class="img" href="https://img.incoherency.co.uk/2512"><img src="https://img.incoherency.co.uk/2512/thumb"></a></p>
<p>You slide in some thin metal tiles to spell out your seed words. Unfortunately, after a bit of abuse, it looks more like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2513"><img src="https://img.incoherency.co.uk/2513/thumb"></a></p>
<p>And you can no longer recover the seed because all the tiles have fallen out.</p>
<p><h2>Cryptosteel Capsule</h2></p>
<p>I particularly liked the design of the <a href="https://cryptosteel.com/product/cryptosteel-capsule/">Cryptosteel Capsule</a>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2511"><img src="https://img.incoherency.co.uk/2511/thumb"></a></p>
<p>It comes with a bunch of thin metal tiles with letters on. To record the seed phrase, you slide the appropriate letters over the central shaft to spell
out the words, then put a retaining clip on the end, and screw the whole thing together inside the capsule.
The design is good because it is all stainless steel, making it well-hardened against fire and water, and the inside of it is sealed, which means for anything to actually damage the data, it would have to break through the outer case first.  
The design is both attractive and easy to manufacture. Unfortunately at &euro;89 it is a bit expensive.</p>
<p>A flaw in the design of the Cryptosteel Capsule is that if you happen to undo the retaining clip and spill the tiles all over the floor, you can no longer
recover the key.</p>
<p><h2>Homemade Capsule</h2></p>
<p>Making a load of tiny tiles with single letters on them sounds annoying and time-consuming, and still comes with the problem that spilling the tiles
results in loss of the key.</p>
<p>However, since I will be having to stamp the letters on the tiles myself anyway, I am free to put more than one letter on each tile! If the tiles are large enough,
each tile can store an entire word of the seed phrase, along with its number, and what's more it can have one word on each side of the washer.
If you spill all the tiles on the floor, you just need to rearrange them in order
of the number, and you've recovered the key. This is an improvement over the Cryptosteel Capsule, but isn't easy to do with a mass-produced device. Perhaps you
could ship it with a letter-stamping kit, although that's a bit burdensome for the average customer to have to deal with. Neatly stamping letters into stainless steel
is not easy.</p>
<p>At first I couldn't think of a good way to produce the tiles and the retaining clip, but eventually I realised that the tiles could be made out of stainless steel
washers, the bar up the middle could be a stainless threaded rod, and the nut at the end could be a stainless nut.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2521"><img src="https://img.incoherency.co.uk/2521/thumb"></a></p>
<p>There isn't room on the washers for more than maybe 6 letters, but BIP39 words are uniquely identified by their first 4 letters, so it's not an issue to
stamp only 4 letters even for longer words.</p>
<p>To make the capsule, I bought a short length of 25mm "303" stainless steel rod off eBay to make the capsule out of. Mostly this was straightforward, start by making the main body
that the washers go inside. This is a length of rod with a hole bored up the middle (but not out the bottom), and a female thread cut in the top. The lid is a
shorter section of rod with a narrower section turned on the end and a matching male thread cut on that. Then it needs a small hole up the middle and an M4
thread to accept the threaded rod up the middle. Some chamfers on the ends, and a bit of polishing, and it's done.</p>
<p>I don't have a lathe tool suitable for cutting internal threads, but I do have a boring bar with a 60-degree tip on it. I improvised by angling the
boring bar so that it cuts an angle suitable for a thread, but the depth of the thread inside the capsule is limited by how deep I can get the tool in before
the back of it crashes into the work. Hopefully this picture illustrates what I mean:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2524"><img src="https://img.incoherency.co.uk/2524/thumb"></a></p>
<p>I had a tool for external threading, but it was a bit too large to thread up to the shoulder, so I ground a flat on the edge of it to clear the shoulder
and it did the job.</p>
<p>I didn't actually have a stainless nyloc nut on hand, so currently there is a plated steel nut on the end, but it could easily be changed and in any case it's not a
serious problem if the nut rusts.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2523"><img src="https://img.incoherency.co.uk/2523/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2522"><img src="https://img.incoherency.co.uk/2522/thumb"></a></p>
<p>It cost me about &pound;14 in materials, and for that I received not just the parts for the capsule, but also the enjoyment of spending the time making it.
In my opinion it is superior to the commercial one, because you don't lose the key even if you spill the washers, and its shorter length means it is easier to stash
away and less likely to get bent if crushed.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/diy-cryptosteel-capsule.html</link>
   <guid>http://incoherency.co.uk/blog/stories/diy-cryptosteel-capsule.html</guid>
   <pubDate>Mon, 20 Jan 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Chassis Design with Finite Element Analysis in FreeCAD</title>
   <description><![CDATA[Finite Element Analysis is a way to calculate the stresses and strains on an
object in various load conditions. The object is modelled as a series of "finite elements" (in our case triangles), and then we specify the locations
of points that can't move (fixed points), and the locations, magnitudes, and directions of forces that are present.]]></description>
   <content:encoded><![CDATA[<p><a href="https://en.wikipedia.org/wiki/Finite_element_method">Finite Element Analysis</a> is a way to calculate the stresses and strains on an
object in various load conditions. The object is modelled as a series of "finite elements" (in our case triangles), and then we specify the locations
of points that can't move (fixed points), and the locations, magnitudes, and directions of forces that are present.</p>
<p>I've recently been doing a Coursera course on engineering: <a href="https://www.coursera.org/learn/machine-design1">Machine Design Part 1</a> (although
it is mostly above my head currently; I think I have missed one or two of the prerequisites), and it
has inspired me to try to do some actual analysis of the <a href="https://incoherency.co.uk/blog/tags/lawnmower.html">racing lawnmower</a> chassis, to inform the design of some improvements.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2473"><img src="https://img.incoherency.co.uk/2473/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2480"><img src="https://img.incoherency.co.uk/2480/thumb"></a></p>
<p><h2>FEA in FreeCAD</h2></p>
<p><a href="https://freecadweb.org/">FreeCAD</a> has support for FEA in the FEM ("Finite Element Method") workbench. It isn't exactly hard to use, although
I found the interface was not very discoverable, and I had to learn how to use it by watching YouTube tutorials. Before starting you need to make sure that you have <a href="http://www.calculix.de/">CalculiX</a> and <a href="http://gmsh.info/">Gmsh</a> installed.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2483"><img src="https://img.incoherency.co.uk/2483/thumb"></a></p>
<p>I have found that CalculiX sometimes complains about "non-positive jacobian determinants" in the analysis. I'm not entirely sure what this means, but it seems fine
to ignore the warning. In previous FreeCAD versions this was fatal and would cause FreeCAD to fail to show the results, but in the latest version it seems not to
matter. I don't know.</p>
<p>I have also found that Gmsh is sometimes unable to produce a mesh. You'll know this has happened if, after trying to create the mesh and being told that it was created
successfully, you are not presented with a visible mesh. You can also check this by looking at the data display for the generated mesh and observing that it has 0
edges, 0 faces, and 0 vertices. If this happens I have found that putting a cap on the maximum element size tends to help Gmsh along (I start high and keep reducing the cap until it works - using smaller elements takes longer to mesh and longer to analyse). You may notice that some of the pictures in this post have much denser triangle meshes than others; this is why. I don't think mesh density would significantly affect the results, other than that a denser mesh will be slightly more accurate.</p>
<p>A limitation of the FreeCAD interface is that you can't apply a force to a small area of a large face. If you want to
add a 4,000 Newton load to the top of a flat plane on your chassis, FreeCAD is going to distribute it over the entire area and provides no way for you to
localise the force to a smaller area. If you really need this, a workaround is to extrude a very short pad (say, 0.01mm tall) in the area you want to apply the force so
that you get to define the shape and size of the force area without significantly affecting the mesh of the part. I didn't bother with this.</p>
<p><h2>Lawnmower Chassis</h2></p>
<p>I started by measuring the key parts of the existing chassis and modelling it in FreeCAD. Most of the chassis is made of 3mm steel sheet, and the rear
axle is 25mm steel round bar.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2472"><img src="https://img.incoherency.co.uk/2472/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2473"><img src="https://img.incoherency.co.uk/2473/thumb"></a></p>
<p>I left off the front axle because I'm confident it's completely overbuilt, and I left off everything above the main plane of the chassis
because it isn't interesting and doesn't really contribute to the strength.</p>
<p>Now comes the hard part: we need to define which faces we want to say are "fixed", and which forces we want to apply, to find out how the chassis
will be stressed. It is easy to create completely unrealistic load scenarios so this really takes some thinking about. For example, initially I thought
a good way to model stress in the rear axle would be to fix one end of it and apply an upward force at the other end, but this is actually not realistic
at all because if sufficient force is applied to one end of the axle, it will result in movement at the other end.
I've found it helpful to
imagine the "fixed" face being firmly attached to a wall or ceiling (upside down if appropriate), and then a weight being hung off the force area. If that's not an accurate
way to model how the chassis will be loaded in use, then it's not an accurate way to model it in FEA either.</p>
<p><h2>Initial tests</h2></p>
<p>The highest stress observed across the 3 test cases was with the top of the chassis fixed in place and an upwards force on one end of the
rear axle. FreeCAD has an option to exaggerate the displacement caused by the applied force to make it easier to see what is happening.
Here I have animated together the displacements from 0x to 10x what was observed from a 4000N load.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2474"><img src="https://img.incoherency.co.uk/2474/thumb"></a></p>
<p>The colouring goes from green where there is no stress to red where there is maximum stress. In this test the greatest stress observed was 485 MPa, and it
was at the top and bottom of the rear axle. 485 MPa exceeds the typical yield strength of steel, so in the case where the mower chassis is attached to the
ceiling upside down, and the entire weight of the mower and driver is hung off a single rear wheel, we can expect the rear axle to bend. Not good.</p>
<p>In practice I don't think it will be this bad because we never have a force against a wheel while the rest of the chassis is held fixed. In reality the axle is
able to push the rest of the chassis out of the way, so I think the actual stress in the axle would be less. Which is why it hasn't bent yet. Nonetheless, it
would be good to move the bearings outwards so that the axle is better supported and can transfer load into the chassis instead of bending.</p>
<p>Another test (although not one I'm particularly convinced by), revealed that the lip along the bottom of the chassis can be heavily-stressed in certain conditions:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2475"><img src="https://img.incoherency.co.uk/2475/thumb"></a></p>
<p>This test has the front edge of the chassis fixed in place, and a 4000N force upwards on the left edge of the rear axle (right in pic). It's an unrealistic model
because a 4000N force on the rear axle would be enough to pick up the rear end, rotating the entire mower around the front axle. The front end wouldn't remain fixed in place. But the test still highlights a potential
weak point.</p>
<p>Also note that this picture has had the rear axle raised up towards the chassis to reduce ride height. This is a change we definitely want to make, so all of the rest
of the analyses have the axle in this new location.</p>
<p><h2>Strengthening the sides</h2></p>
<p>An easy way to strengthen the sides of the chassis is to weld some box section to the bottom of them. Here I've added lengths of box section 25mm across with 2mm wall
thickness:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2476"><img src="https://img.incoherency.co.uk/2476/thumb"></a></p>
<p>The maximum stress (in the admittedly-dubious test) is reduced from 813 MPa to 510 MPa (-38%), and the area of max. stress is no longer on the lip underneath, it's now the axle, so the stress on the lip underneath the chassis is reduced by even more than 38%.</p>
<p><h2>Moving the axle mounts out</h2></p>
<p>To move the axle mounts out I modelled a small frame on each side made of 25mm box section with 2mm walls. The bearing block is then attached to the end (in real
life this would be bolted on, but in the model it's all just a solid piece of steel), and the axle goes through the bearing block.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2479"><img src="https://img.incoherency.co.uk/2479/thumb"></a></p>
<p>With the top plane of the chassis fixed and a 4000N load applied to one end of the axle (the highest-stress load condition), we get this (displacement exaggerated 20x):</p>
<p><a class="img" href="https://img.incoherency.co.uk/2478"><img src="https://img.incoherency.co.uk/2478/thumb"></a></p>
<p>The maximum stress is 424 MPa, at the corner of the frame, where it attaches to the chassis. In the same test on the original chassis model but with the
ride height lowered, the max. stress was 496 MPa (in the axle), so adding this frame only reduced the stress by 15%, although it did move it out of the axle.
I expected a better reduction though.</p>
<p>I thought part of the problem here might be that
the little frame is only attached to sheet metal, which means there's a relatively low joint area between the frame and the chassis, so I tried adding
an extra piece of box section to the frame:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2480"><img src="https://img.incoherency.co.uk/2480/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2481"><img src="https://img.incoherency.co.uk/2481/thumb"></a></p>
<p>Now in the same test, the maximum stress is 328 MPa, which is now 44% lower than before. Much better. The stress is still concentrated in a small area
at the edge of the frame, though, so probably more support here would help even more. When I actually build this, I plan to start with what is modelled here and then
overbuild it based on whatever seems reasonable to me at the time. Triangulating the support by adding a tube from the end of the frame to the top face of the chassis wouldn't hurt.</p>
<p><h2>Engine mounts</h2></p>
<p>The test with the axles fixed and a downwards force on the top plane of the chassis was quite surprising. In this test the maximum stress generated is quite small (about 80 MPa), but the displacement of the chassis is quite large, because most of the stress is taken up in a large thin piece of sheet metal. Exaggerated 20x we get:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2482"><img src="https://img.incoherency.co.uk/2482/thumb"></a></p>
<p>You can see that the sheet metal just flexes with the force applied. The major forces acting in this way are the weight of the driver and the weight of the engine.
The driver's weight is distributed to the very edges of the rear of the chassis by the box that the seat sits on, which you can see in this photograph:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2472"><img src="https://img.incoherency.co.uk/2472/thumb"></a></p>
<p>So the driver's weight isn't trying to flex the sheet metal.
But the engine is bolted to the middle. I think it would be worth adding some reinforcement around the holes that the engine is bolted to, to reduce this flex.</p>
<p>You can also see that the stress is concentrated around the holes in the chassis (the orange/red areas). I don't think this is a problem, because the magnitude of
the stress is relatively small, but if I can be bothered I might weld some steel plates over some of the holes just to close them up.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/freecad-fea.html</link>
   <guid>http://incoherency.co.uk/blog/stories/freecad-fea.html</guid>
   <pubDate>Tue, 07 Jan 2020 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>My RC2014 Web Server</title>
   <description><![CDATA[I wrote a web server for my RC2014. It runs from CP/M, which has no built-in concept of networking,
so I had to implement every layer of the networking stack, which in this case is SLIP, IP, TCP, and HTTP.
It totals about 1200 lines of C, all of which was written on the RC2014 in the ZDE 1.6 text editor, and compiled with the Hi-Tech C compiler.]]></description>
   <content:encoded><![CDATA[<p>I wrote a web server for my RC2014. It runs from CP/M, which has no built-in concept of networking,
so I had to implement every layer of the networking stack, which in this case is SLIP, IP, TCP, and HTTP.
It totals about 1200 lines of C, all of which was written on the RC2014 in the <a href="https://techtinkering.com/2008/10/21/installing-zde-1-6-a-programmers-editor-for-cpm/">ZDE 1.6 text editor</a>, and compiled with the <a href="https://techtinkering.com/2008/10/22/installing-the-hi-tech-z80-c-compiler-for-cpm/">Hi-Tech C compiler</a>.</p>
<p><a href="https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol">SLIP</a> is dead easy, but claiming that the project implements IP, TCP, and HTTP might be a bit of a stretch. It does the absolute bare minimum required to trick people into thinking that it works. The most obvious shortcomings are that it is really slow and it has no way to retransmit dropped packets, which I'll explain further down.
But it <i>does</i> (appear to) work. You can browse a website being served by my RC2014 at <a href="http://moonship.jes.xxx:8118/">http://moonship.jes.xxx:8118/</a>, assuming it is still up by the time you read this. It is extremely slow, for various reasons, and only supports 32 simultaneous open connections, the combination of which means it is very easy to DoS (even by accident, but please don't do so on purpose).</p>
<p>I have made <a href="https://www.youtube.com/watch?v=E3hSGMdmdxc">a short video showing the RC2014 serving a web page</a> in case you want to see what it looks like with the console output and <a href="https://incoherency.co.uk/blog/stories/rc2014-frontpanel.html">blinkenlights</a>.</p>
<p>You can <a href="https://github.com/jes/cpmhttpd">get the code on github</a>, but I wouldn't recommend using it. It even includes a CP/M executable in case you want to try it on your own machine. It doesn't depend on anything RC2014-specific, so as long as your CPU supports Z80 instructions and your CP/M connects the "reader" and "punch" devices to a serial port, you can then plug that serial port into another computer that speaks SLIP and it ought to work. The IP address is fixed at 192.168.1.51. If you want to change that you can probably find it in the binary and hexedit it. I suspect you should only need to change it in one place, but I haven't actually checked.</p>
<p><h2>Challenges</h2></p>
<p>I've written a web server in C before, so I was expecting the lower-level networking stuff to be the only hard part about this project. If I had written it on a modern machine and cross-compiled to CP/M, that would probably have been true. But I wanted the full retro experience, so I wanted to develop it all inside CP/M. That meant all of the development tools I know and love are missing. It's just a text editor and a compiler. The text editor is no vim and the compiler is no gcc, and there's nothing remotely resembling gdb or valgrind. Fortunately, I was able to make use of Wireshark by running it on the Linux end of the SLIP connection. If I had to debug all of the networking code with printfs I would have certainly been driven mad.</p>
<p>It takes about 7 minutes to compile the server, which makes for a frustratingly-slow edit-compile-test cycle.</p>
<p><h3>Compile-time memory usage</h3></p>
<p>The "transient program area" on my system is only 54 kilobytes. There is more memory available via bank-switching, but the C compiler doesn't know how to use it. I've found that it runs out of memory very easily when compiling even small programs. Sometimes it gives you a helpful "Out of memory" message, but usually it gives unintelligible nonsense (either incorrect error messages, or just random bytes printed to the console). When this happens you need to split your source file into 2 smaller ones that can be compiled independently, which is quite annoying but relatively easy to do.</p>
<p>I ended up calling my networking files "net.c", "net2.c", and "net3.c" and the web server files "httpd.c", "httpd2.c", "httpd3.c", and "httpd4.c". The code in each file is vaguely grouped by purpose, but not much. If it was left up to me, there would probably have only been 2 source files (net.c and httpd.c).</p>
<p><h3>Text editor</h3></p>
<p>I haven't figured out how to copy and paste in ZDE and I'm not sure whether it's possible. This is a problem when it comes to splitting a source file into 2, because it means I don't know how to copy text out of one file and paste it in another. The solution I've come up with is to use CP/M's COPY.COM program to create a copy of the source file, and then delete the top half of the functions in one, and delete the bottom half in the other. That way I've moved some of the functions to a new file without having to type them all out again.</p>
<p>ZDE has other weirdness, such as using key combinations that I've never seen in any other software and sometimes spuriously drawing an "I" character at the end of a line. But it is a substantial improvement over ED.COM. It's usable.</p>
<p><h3>Memset</h3></p>
<p>The Hi-Tech C compiler's memset() prototype in stdlib.h is <tt>extern void * memset(void *, int, size_t)</tt>. The usage of "int" and "size_t" implies that the second argument is the value, and the third argument is the length. This is the correct order of arguments for memset. Unfortunately, the implementation of memset uses the arguments the other way around, so you have to swap them in your code, which means your code is no longer portable to other compilers, and it also means all C programs that use memset won't quite work properly. I spent quite a few hours stuck on this.</p>
<p><h3>Open files</h3></p>
<p>The C library only supports 8 simultaneous open files, and 3 of these are taken up for stdin/stdout/stderr. If we want to support 32 simultaneous clients, we need to keep track of our position in 32 simultaneous files. I solved this problem by creating my own "jesfile_t" which is kind of like a "FILE *" except you're allowed more of them. It works by remembering the filename and byte offset within the file. Whenever you try to read from the file, it opens it, seeks to the current offset, performs the fread() call, updates its byte offset, and closes the file. That means it only ever has 1 file open at a time, but it can keep track of its position in all 32. <a href="https://github.com/jes/cpmhttpd/blob/master/httpd4.c#L49">The implementation</a> is relatively simple. I only implemented "jesfopen()", "jesfclose()", and "jesfread()" because that's all I needed, but you could also use the same idea to replace fwrite(), fgets(), etc. Indeed, that is essentially all a "FILE *" does internally: it just keeps track of which file you're working with and where you are within it.</p>
<p><h3>Stale connections</h3></p>
<p>With a fixed number of connection slots, and no way to timeout idle connections, we can easily end up with a full connection table and no active clients! For example, if 32 clients opened connections and then just walked away, that would fill up all 32 slots, and no new clients would be able to connect. To work around this, the server keeps track of the order in which the connections were last active. In the event that it needs to allocate a new connection slot, and there are none empty, it just reuses the one which was least-recently active. Probably in this case it should send a "reset" packet to the other side of the connection that is being forgotten, but it doesn't. It just silently forgets about the old connection.</p>
<p><h3>Reading from the serial port</h3></p>
<p>The serial port is represented inside CP/M as the "reader" and "punch" devices. I guess it was originally expected that the only stream I/O device apart from the console would be a paper tape reader and punch. There is a blocking BDOS call (system call) for each of reading a byte from the reader and writing a byte to the punch. There are comparable blocking functions for the console, but the console also comes with a "get console status" call that will tell you whether reading a byte would block. There is no such function for the reader, which means you just have to ask for a byte and then sit there until you get one. CP/M literally has no way to find out whether reading a byte from the reader will block.</p>
<p>My RC2014 has the reader backed by a Z80 SIO/2 module, which <i>does</i> have a way to tell you whether or not a read will block, so it would be relatively easy to switch to driving the SIO module directly, instead of using the CP/M BDOS call, but currently there is nothing useful the web server can do in the absence of any input bytes, so there's no harm in blocking.</p>
<p>One downside of blocking on the reader is that it prevents ^C from exiting the program. There is in fact no way to exit the program until the read call returns, which means to exit it you need to either reset the machine, or type ^C and then send it some bytes. It seems as though the "read reader" BDOS call checks whether you've typed ^C at the console, but only upon entry. If you type ^C after it's started blocking, it doesn't notice until the read call returns and another read call is entered and it checks again.</p>
<p><h3>Send buffering</h3></p>
<p>The MTU of the SLIP link is 256 bytes. With TCP and IP headers, that becomes 296 bytes. In order to retransmit dropped packets, we'd need to store a copy of every packet that has been sent, and can only discard it after it has been ACK'd. We support 32 simultaneous clients, so if we allocated enough buffer space to store only 6 packets per client, that would exhaust the entire transient program area before we've even started. So far I'm just storing the last sent packet for each client (even though there's no facility to ever retransmit any). Thanks to CP/M's shortage of development tools, I have no idea how much memory the program uses while running. The binary is 21K on disk, but it does some dynamic allocation as well.</p>
<p><h3>Packet retransmission</h3></p>
<p>There are two times that a TCP implementation might want to retransmit a packet.</p>
<p><h4>Duplicate ACK</h4></p>
<p>If you receive 2 acknowledgments of the same sequence number, it means the remote side has discovered that it has missed a packet. For example, assume we sent packets with sequence numbers 1, 2, and 3. If the remote side receives no. 1, and acknowledges it, and then receives no. 3, it can't acknowledge no. 3 because it hasn't seen no. 2. In this case it sends a duplicate acknowledgment for packet no. 1. When the sender receives the duplicate acknowledgment of packet no. 1, it knows that packets may have been dropped. If the sender receives a third acknowledgment for packet no. 1, it must retransmit no. 2.</p>
<p>In our case, we only ever send 1 packet at a time, then wait for it to be acknowledged, before we'll send another. This is both bad for bandwidth (because we need to wait 1 entire round-trip-time between every 256 bytes of content), and it means we can <i>never</i> receive a duplicate ACK. So in this case, we don't retransmit because, even if that logic were implemented, we have no way to trigger duplicate ACKs in the first place.</p>
<p><h4>Timeout</h4></p>
<p>If the sender sees that too much time has passed since sending a packet, and no acknowledgment has yet been received, it must retransmit the packet. This means the sender must have some way to measure the passage of time. Unfortunately, my RC2014 does not have any way to measure the passage of time. The best way to do this would be with a Z80 CTC module, but I haven't bothered for now.</p>
<p>In the absence of some sort of timer interrupt, we could conceivably count instructions, or loop iterations, to get an estimate of how much time has passed, and retransmit once the estimate has got too high. Unfortunately, the CP/M BDOS call to read from the reader blocks until bytes are available. Firstly, we can't pre-empt it to retransmit a packet if we decided we wanted to. Secondly, we don't know how long it blocked for, so we don't even know if it's time yet to retransmit a packet.</p>
<p>For these reasons, my web server does not retransmit packets in this case either. This means that if a packet is dropped, the connection just hangs. Not ideal, but it's rare enough not to matter too much for a toy project.</p>
<p><h2>Improvements</h2></p>
<p>The most important improvement is to add a CTC to facilitate timed retransmission, and also drive the SIO device directly instead of via the BDOS so that it can be used in a non-blocking way. After that, to improve bandwidth it would be good to come up with a way to transmit several packets without getting the acknowledgments in between. We could allocate a fixed buffer large enough to store say 8K of sent-but-not-yet-acknowledged packets, and allocate space in this buffer across different clients as and when they need it. In the event that there is not enough space in the buffer, we just can't send another packet yet.</p>
<p>There are also probably some bugs in the TCP state machine. I made no effort to actually faithfully implement TCP (I haven't even read the RFC). It just goes through the motions enough to work in the normal case.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/rc2014-web-server.html</link>
   <guid>http://incoherency.co.uk/blog/stories/rc2014-web-server.html</guid>
   <pubDate>Tue, 10 Dec 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Design and Implementation of a Z80 Computer Front Panel</title>
   <description><![CDATA[I designed and built a front panel for my RC2014. It allows you to view
and alter the contents of memory, read and write to IO devices, and single-step through instructions.
The RC2014 backplane basically just puts the Z80 CPU pins directly on the bus, so the same panel would work
unmodified against almost any Z80-based computer, as long as you broke out the bus onto the 60-pin ribbon cable.]]></description>
   <content:encoded><![CDATA[<p>I designed and built a front panel for my <a href="https://rc2014.co.uk/">RC2014</a>. It allows you to view
and alter the contents of memory, read and write to IO devices, and single-step through instructions.
The RC2014 backplane basically just puts the Z80 CPU pins directly on the bus, so the same panel would work
unmodified against almost any Z80-based computer, as long as you broke out the bus onto the 60-pin ribbon cable.</p>
<p>This is what it looks like:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2436"><img src="https://img.incoherency.co.uk/2436/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2433"><img src="https://img.incoherency.co.uk/2433/thumb"></a></p>
<p>And I made a video demonstrating its use:</p>
<p><ul>
<li><a href="https://www.youtube.com/watch?v=q5BEHFvPDhc">Programming the RC2014 using the front panel</a></li>
</ul></p>
<p>This is a pretty long post because I want to document everything. So unless you're planning to make your own, you might prefer
to just look at the pictures, and only read the parts that look interesting.</p>
<p><h2>Case</h2></p>
<p>Bill Buzbee used a 6U 19" rackmount enclosure for <a href="http://homebrewcpu.com/">Magic-1</a>,
but that's a bit bigger than I need. I went on eBay and looked for medium-sized metal enclosures for electronics projects.
There was a fair range available, but most of them were quite expensive. I ended up settling on the cheapest
one I could find, which was still nearly &pound;40.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2435"><img src="https://img.incoherency.co.uk/2435/thumb"></a></p>
<p>Despite being the cheapest available, I'm very happy with this case. It is made from aluminium, it has rubber feet on the bottom, vent holes on the
top and bottom, all of the panels are easily removed to gain access to the insides, and it's available in a
wide variety of sizes. I would like to use the same type of case in future projects.</p>
<p><h2>Logic</h2></p>
<p>The only reason I thought I might be remotely capable of this project in the first place is because of an excellent
article in the <a href="https://ia801201.us.archive.org/31/items/Kilobaud197806/Kilobaud%201978-06.pdf">June 1978 issue of Kilobaud
Magazine</a>. It's the one starting on page 26: "Home-Brew Z-80 System ... Part 1: front-panel construction".
Incidentally, the magazine is a fascinating read just for the products that are advertised in it, even if you ignore the actual
content! It includes such gems as "honestly: how many reasons do you need to make sure your next micro-processor
is the original, genuine KIM<sup>TM</sup>?", and "Intertec's SuperDEC: pull out the guts & screw in the brains".</p>
<p><a class="img" href="https://img.incoherency.co.uk/2460"><img src="https://img.incoherency.co.uk/2460/thumb"></a></p>
<p>But even with the writeup in Kilobaud Magazine, I don't have a lot of experience of designing electronics, and it seemed too complicated
for me to be able to get it to work. So I got rid
of the auto-increment on the address bus, and just had manual switches instead. I simplified the "deposit"
logic so that the automatic timing of the "write" pulse is not required, instead replacing it with a manual switch. And I used separate
switches for the address and data inputs instead of using the same switches to do both. With these changes, I ended up not being able to
use much of the design from the magazine, although reading it was still very instructive and I don't think I'd have even known
where to start if I was on my own.</p>
<p>How people managed to get this stuff to work in a time before the Internet is beyond me. There's just <i>so</i> much to understand.
And unlike software, you can't just edit and recompile if it doesn't work. You have to physically buy the components, and solder
them together. It's a wonder that computers ever got off the ground in the first place.</p>
<p>I designed the schematic and PCBs in <a href="http://kicad.org/">KiCad</a> which is excellent software.</p>
<p><h4>Reset and power</h4></p>
<p>The most basic functions required of the front panel are the ability to turn the power on/off and to reset the
CPU. I used a toggle switch for the power, with an indicator LED, and a momentary switch to pull the RESET line low.</p>
<p><h4>BUSRQ</h4></p>
<p>The Z80 has an active-low line called BUSRQ which is used to tell the CPU to stop what it's doing so that something else can interact with
memory. When the CPU has accepted the bus request, it pulls the BUSAK line low to indicate that the bus is now available.
The front panel will have a switch to let the operator pull the BUSRQ line low, and an indicator to show the state of BUSAK.</p>
<p>We need some logic to make sure that we only try to interact with the bus when we have asked for BUSRQ and have been given BUSAK.
I called this signal "HAVEBUS". HAVEBUS is high when we have the bus. There is also "INVHAVEBUS"
which is the inverse of HAVEBUS, useful for controlling active-low inputs. I used a 74LS02 quad NOR gate (there are 4 gates per chip) to generate HAVEBUS. HAVEBUS = BUSRQSW NOR BUSAK.
NOR is basically AND for active-low inputs, via <a href="https://en.wikipedia.org/wiki/De_Morgan's_laws">De Morgan's law</a>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2444"><img src="https://img.incoherency.co.uk/2444/thumb"></a></p>
<p>(Some of the parts in the schematic say 74HCTxx but I actually used 74LSxx for everything. I don't really know what the differences are.).</p>
<p>BUSRQSW is the state of the BUSRQ switch on the front panel, which is distinct from the state of the BUSRQ line on the bus.
Instead of connecting the switch directly to the line on the bus, it is instead used to drive a 74LS125 buffer. That way, when BUSRQSW is low,
the BUSRQ line is pulled low, but when BUSRQSW is high, the BUSRQ line is left floating (it has a pull-up resistor on the CPU card on the RC2014), so that other devices can use it if they like.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2445"><img src="https://img.incoherency.co.uk/2445/thumb"></a></p>
<p><h4>Address bus</h4></p>
<p>The address bus LEDs will be permanently controlled by the signals on the address bus. A pair of 74LS244 8-way buffers are used
so as not to load up the bus with the current required to power the LEDs.</p>
<p>The address bus switches will control the bus when HAVEBUS is true, but otherwise they need to have no effect. Another pair
of 74LS244 buffers are used for this, with the active-low "output enable" pins driven by the INVHAVEBUS signal.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2447"><img src="https://img.incoherency.co.uk/2447/thumb"></a></p>
<p>The A0SW..A15SW signals come from the switches on the panel. In one position the switch connects the signal to 0v. In the other
position the switch disconnects the signal, allowing a 4k7 resistor to pull it up to 5v.</p>
<p><h4>Data bus</h4></p>
<p>Just like with the address bus, the data bus LEDs are permanently controlled by the signals on the databus, via a 74LS244 buffer.</p>
<p>Unlike the address bus, the data bus switches only affect the data bus when we are in "writing" mode, otherwise we would never
be able to read the contents of memory. The buffer that drives the data bus is activated by the "INVDBUS_EN" signal (inverse
of "data bus enable"), so that it only drives the bus when the data bus switches are enabled, by another switch on the panel.
Calling the switch "data bus enable" is crazy, so the actual switch ended up getting called "RD/WR", as it essentially switches
between reading mode and writing mode.</p>
<p><h4>Memory/IO, reading/writing</h4></p>
<p>I wanted to be able to read and write to IO ports as well as memory, so a switch on the front panel lets you select between
the MREQ and the IORQ pin of the bus. Just like BUSRQ, this signal is buffered through a 74LS125 so that the bus lines
are left floating when they're not being asserted.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2448"><img src="https://img.incoherency.co.uk/2448/thumb"></a></p>
<p>MEMIOSW is just the state of the MEM/IO switch on the front panel.</p>
<p>Similarly, we need to be able to switch between reading mode (which asks the memory to read out its contents, and disconnects
the data bus switches) and writing mode (which connects the data bus switches to the bus, and allows usage of the WRITE switch on the panel
to perform a write operation).</p>
<p>I made a logic error in driving the RD line of the bus. The DBUS_EN signal in my front panel is high when the RD/WR switch
is in the WR position (i.e. we're in writing mode) and HAVEBUS is true. The 74LS125 buffer's "output enable" pin is active-low,
so I drove the RD signal buffer with the inverse of DBUS_EN, so that RD would be enabled when we're not in writing mode. Unfortunately,
that means that RD is enabled even when HAVEBUS is false! That means the memory is always trying to put its contents on the data bus
even when the CPU is trying to write, which means the two are fighting over the contents of the data bus, some wrong bits get
written to memory, and the executing code quickly goes off the rails. I only found this out later.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2449"><img src="https://img.incoherency.co.uk/2449/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2450"><img src="https://img.incoherency.co.uk/2450/thumb"></a></p>
<p>The WR line is driven similarly to the RD line, except with the condition that not only do we have to be in writing mode, but also
the WRITE switch needs to be pressed. The reason for the separation of the writing mode (which puts the data switches on the bus) and
the WRITE switch (which asserts WR) is to avoid the race condition that occurs if both happen simultaneously. When releasing WR, you
need to ensure that WR is released before the contents of the data bus disappear. The project in Kilobaud magazine did this by using
"one-shot" ICs to put the data switches on the bus and to trigger WR, and to make sure that the WR pulse is shorter than the data pulse,
so that the write always occurs with the correct data. My solution requires less logic, and gives finer control of the bus, but
means you have to manually switch between RD and WR.</p>
<p><h4>Single-stepping</h4></p>
<p>I copied the single-stepping logic straight out of the Kilobaud Magazine article. This is actually the part that I was most concerned
about not working, because I understood it the least. For this reason, it is also the only part that I tested on a breadboard before
ordering the PCBs. (Testing the entire thing on breadboards is impractical because of the number of components and connections required.
I'm not <a href="https://eater.net/">Ben Eater</a>).</p>
<p>This is the logic I eventually settled on:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2451"><img src="https://img.incoherency.co.uk/2451/thumb"></a></p>
<p>U14 is a 74LS74 <a href="https://en.wikipedia.org/wiki/Flip-flop_(electronics)#D_flip-flop">D flip-flop</a>, U15 is a 74LS121 one-shot ("monostable multivibrator"). U7 is a 74LS02 NOR gate and U3 is
a 74LS04 inverter. The inputs here are STEPSW, SINGLESW, and M1. The output is WAITING, which is just used to drive a buffer
to pull the WAIT line low.</p>
<p>SINGLESW is the switch that selects between single-step mode and the normal "run" mode. When we're in "run" mode, the WAIT line
never gets asserted. STEPSW is the debounced switch that allows us to step forward by one instruction. M1 is a signal from the Z80
that goes low during the opcode fetch cycle, and is high the rest of the time.</p>
<p>The idea here is that when we're in single-step mode, we hold the WAIT line low most of the time. When the "step" switch is pressed,
we let go of WAIT by clocking VCC into the D flip-flop via the data pin, until we see M1 go low (which means we've started
the next instruction), at which point we pull WAIT low once again by sending a short low pulse to the reset pin of the D flip-flop.</p>
<p>When testing it on the breadboard, I originally had connected M1 directly to the reset pin of the D flip-flop and did not include
the one-shot IC. This doesn't work because as soon as the CPU enters the M1 state,
the reset pin of the flip-flop is held low, so pressing the step switch has no effect. The one-shot just means that the D flip-flop gets put back into
a state where the STEPSW input can allow it to clock VCC in via the data pin. I was glad I tested it on a breadboard before committing to the design.</p>
<p><h4>Switch debouncing</h4></p>
<p>I copied the switch debouncing mechanism from the Kilobaud Magazine article. It uses dual-throw switches to
activate either the "set" or "reset" pin of a 74LS279 <a href="https://en.wikipedia.org/wiki/Flip-flop_(electronics)#Simple_set-reset_latches">S-R latch</a>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2452"><img src="https://img.incoherency.co.uk/2452/thumb"></a></p>
<p>STEP_S and STEP_R are connected to opposite throws of a switch, and pulled up to 5v with a 4k7 resistor.
The common pole of the switch is connected to 0v. When the switch is pressed from (say) the STEP_S position
to the STEP_R position, any bouncing on the release of STEP_S, or the contact of STEP_R, has no effect, because the flip-flop maintains its
state when neither of the inputs are active.</p>
<p>Not all of the switches need to be debounced, so most of them do not have any debouncing. For example some bouncing of
the address and data switches, or the reset switch, has no ill effect.</p>
<p><h4>Status lights</h4></p>
<p>The only logic remaining is to generate the various status lights at the bottom of the panel.</p>
<p>MRD and MWR tell you when there is a memory read or write happening. Likewise, IORD and IOWR tell you when there
is an IO read or write. The HALT light comes on when the CPU has halted (caused by the "halt" instruction).
The WAIT light comes on when something is telling the CPU to wait. This will normally be the single-stepping logic
of the front panel, but can also be caused by IO devices that need more time to handle an IO request. The TX and
RX lights indicate serial line activity, and DISK indicates CompactFlash card activity.</p>
<p>MRD, MWR, IORD, and IOWR are made by combining the Z80's MREQ, IORQ, RD, and WR signals into a form that makes
more sense to humans (e.g. MRD means MREQ and RD are both active, etc.). BUSRQ, HALT, and WAIT are taken from the bus and inverted to drive the LED because they are active-low.
TX1, RX1, TX2, and RX2 are also inverted, because although the serial signals are active-high, the serial lines are in the high
state when idle.
The CompactFlash card activity is not a signal that is exposed
on the bus so it will be provided by a jumper from the CompactFlash module.</p>
<p>If you're interested, you can see the entire schematic for the logic PCB here:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2446"><img src="https://img.incoherency.co.uk/2446/thumb"></a></p>
<p>The layout of the schematic is a bit confusing, and there is also some inconsistency in the labelling regarding which of my signals are active-low
and which are active-high. But it's there to look at if you want.</p>
<p><h2>PCB Design</h2></p>
<p>There are 3 things our logic PCB needs:</p>
<p><ol>
<li>connection to the RC2014 bus</li>
<li>connection to the LEDs and switches on the front panel</li>
<li>implementation of the logic</li>
</ol></p>
<p>I used a 2x30 "IDC60" ribbon cable, and designed a small PCB to break out the bus on to the ribbon cable, to
then carry the signals to/from the logic PCB to be mounted on the back of the front panel.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2453"><img src="https://img.incoherency.co.uk/2453/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2456"><img src="https://img.incoherency.co.uk/2456/thumb"></a></p>
<p>It simply connects each pin from the RC2014 bus to the corresponding pin of the IDC60 connector.</p>
<p>To connect to the LEDs and switches I left pads on the PCB for wires to be soldered onto. The LEDs and switches all share
a common ground connection, and the remaining wire (or 2, on dual-throw switches) is to be soldered to a pad on the PCB.</p>
<p>And finally, to implement the logic, I just had to position all of the components specified in the schematic, and then run
traces between them. I found this difficult as there is a lot more going on on this board than on others I've done before.
I started by manually spreading the components out and moving them around until the "rat's nest" looked about as simple
as I could get it, and then routed traces until I was done. I made extensive use of KiCad's "push-and-shove" router here.
It would have been very difficult to route everything manually. One side of the PCB has empty spaces filled with copper connected to 0v, and the
other side has empty spaces filled with copper connected to 5v.</p>
<p>I also added a mounting hole in each corner of the PCB, to facilitate attaching it to the back of the front panel.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2455"><img src="https://img.incoherency.co.uk/2455/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2454"><img src="https://img.incoherency.co.uk/2454/thumb"></a></p>
<p>(KiCad thinks the pads for the LEDs and switches are actually pin headers, so it renders them as pin headers in the 3d view, but most of those
pin headers just have wires soldered on instead in the actual build).</p>
<p>The 6 large ICs mounted horizontally are the 74LS244 buffers for the address/data LEDs and switches. The switch connections
each have a corresponding pull-up resistor, and the LED connections each have a corresponding current-limiting resistor.
There is a bypass capacitor for each IC. These are probably not necessary but can't hurt, they're just there to eliminate
flakiness caused by voltage fluctuations.</p>
<p>I ordered these PCBs from <a href="https://jlcpcb.com/">JLCPCB</a>, because I used them <a href="https://incoherency.co.uk/blog/stories/process-controller.html">last time</a>
and was happy with the quality and price. They sprung a $5 discount on me at the checkout step, which was surprising and seems counter-productive,
because I was going to buy anyway. But whatever, I'll take the discount.</p>
<p><h2>Panel Design</h2></p>
<p>I designed the front panel layout in Inkscape. I would have preferred to use some real parametric 2d CAD
software, but I don't know anything suitable. FreeCAD's sketch editor is good, but is aimed at 3d modelling, and I don't know if you can convert the sketch
into something that has text and colour and is suitable for printing. Inkscape was adequate really, but for example if you want to alter the spacing between
the switches, you have to manually move every single switch which seems more like a job for the computer than the human.</p>
<p>(Update: <a href="https://www.stavros.io/">Stavros</a> points out a better way to alter the spacings: you don't have to move all the switches manually in Inkscape, you can just move the farthest two where you want them and click "align: equal spacing between").</p>
<p><a class="img" href="https://img.incoherency.co.uk/2434"><img src="https://img.incoherency.co.uk/2434/thumb"></a></p>
<p>The holes at left and right are to mount the panel to the case. These holes already existed in the panel.
The 2 holes at top and 2 at bottom are to mount the PCB.</p>
<p>The Kilobaud Magazine article suggested that it was a bad idea to space all of the data and address switches equally, and they should
instead be grouped into 3s or 4s to facilitate octal or hex data entry. I opted instead to space the switches equally, but to draw
a line between the groups of 4 to visually separate them. This seems to be more than good enough. I didn't have any trouble
discerning the nybble boundaries while using the switches.</p>
<p>I pinched the RC2014 logo from the header image on the RC2014 website and doctored it in the Gimp to make it look more reasonable
against the beige background. I also kind of wanted to add one of those "Z80 Inside" logos but couldn't think of a suitable
place to put it.</p>
<p><h2>Panel Build</h2></p>
<p>The first thing we need to do to the panel is drill holes for the LEDs, switches, and screws. I printed off a draft copy
of the front panel layout, sellotaped it to the metal panel, and centre-punched all of the hole locations.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2419"><img src="https://img.incoherency.co.uk/2419/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2420"><img src="https://img.incoherency.co.uk/2420/thumb"></a></p>
<p>I then used these punch marks to drill a pilot hole, and then expand the holes to 7mm for the LEDs and 6mm for the switches.
I didn't get the locations perfect, but they're all within about 1mm of where they need to be, which should be good enough.</p>
<p>I put a single LED and switch in the panel to check that they fit OK.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2423"><img src="https://img.incoherency.co.uk/2423/thumb"></a></p>
<p>Seems fine, although I didn't like how far the switch sticks out of the panel. I solved this by 3d printing some plastic
spacers to push the switch further inside.</p>
<p>I had ordered a high-quality print of the front panel artwork from a company called Doxdirect. I ordered it on 300gsm paper,
and with a matt lamination. I was very disappointed with the quality of the lamination, it almost seemed like
it wasn't laminated at all. I wouldn't get laminated prints from Doxdirect again. The quality of the actual printing is excellent,
but the lamination is far too thin. I actually complained about this, and they made me another one, but the second one
was exactly the same as the first.</p>
<p>The next job is to cut out the holes. I wasn't sure of the best way to do this.
I made a cutting tool on the lathe which is basically a hollow steel rod of the correct diameter, with a sharpened end.
This is based on something I remember reading in the Magic-1 build diary. I tried to use the tool by hand but it was too difficult.
<a href="http://dartoxia.com/">Ben Gazzard</a> suggested putting it in the drill, which made it a lot easier.
Once again, I didn't get all the holes in exactly the right place, but they're all close enough. Making holes in precise places is
really a task for a machine, not a person.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2440"><img src="https://img.incoherency.co.uk/2440/thumb"></a></p>
<p>You can see the cutting tool at the left of that photo. I did the largest holes first, then made the tool smaller
to do the smaller holes. It worked OK but I think I'd put the sharpening on the outside rather than the inside if I
were to do it again. It was quite hard to use because the shape on the inside tended to compress the circle of paper that was being removed, making
it hard to cut all the way through.</p>
<p>Since there were only 6 of the smaller screw holes, I cut these carefully by hand using a knife, rather than modify the cutting tool.</p>
<p>With all of the LEDs and switches installed, the back of it looked like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2427"><img src="https://img.incoherency.co.uk/2427/thumb"></a></p>
<p>You can just about see the blue 3d printed spacers under the switches. The switches that are narrower and black are the momentary switches, that automatically
spring back as soon as you let go, used for RESET, STEP, and WRITE. The panel-mount LED holders are quite good, I'd never used them before. You just push
the black plastic clip into the panel, and then push the LED into the clip, and it all stays in place.</p>
<p><h2>PCB Build</h2></p>
<p>There's something satisfying about pristine PCBs that show up in the post, manufactured to your exact specifications, but not yet with any
components soldered on.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2442"><img src="https://img.incoherency.co.uk/2442/thumb"></a></p>
<p>While soldering components on the PCB I noticed a number of comical mistakes. I had placed some vias that
don't connect to anything on the other side, and there are big detours in some traces that don't go around
anything. The reason for this is that this is by far the most
complicated PCB I've done, and routing the last few traces took me a very long time. There were
a lot of false starts and undoing, with trying to get everything connected, and once
it finally passed the "design rules check", I just wanted to leave it alone and not mess with it any more, so I didn't
go back and clean up the mess.</p>
<p>After soldering all the components to the PCB I moved on to soldering on wires to the LEDs and switches. I laid the front panel and the PCB
both upside down, next to each other, and ran the wires across, so that the two halves can then be "folded" together to form the complete
assembly.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2457"><img src="https://img.incoherency.co.uk/2457/thumb"></a></p>
<p>You can see in that picture that I've soldered some of the wires for the status lights, and I've also connected all of the ground connections of
the LEDs and switches together. I did this for the LEDs by bending the negative leg to reach the adjacent LED and then soldering them together,
and I ran a piece of uninsulated wire along each row of switches.</p>
<p>Soldering the wires to the LEDs was quite difficult owing to my unfortunate disability: I only have 2 working hands. Instead of trying to hold the
wire, solder, and soldering iron simultaneously, I first put a blob of solder on the leg of the LED, and then re-melted the blob while poking the
wire into it. It worked OK but it was quite time-consuming and they're not particularly good joints. The switches were easier as they have holes on
the pins that do a good enough job of keeping hold of the wire.</p>
<p>With the first few LEDs wired up, I plugged in the ribbon cable and tried to switch the computer on to verify that they flash as expected.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2428"><img src="https://img.incoherency.co.uk/2428/thumb"></a></p>
<p>The lights that were connected did flash as expected, but the computer didn't actually work. This was puzzling. I assumed that some of the
logic must be in a wrong state due to the unconnected switches, so I went and connected the important switches and tried again. It still didn't work.</p>
<p><h4>Blunder 1</h4></p>
<p>For a quick sanity check, I ran my finger across all of the ICs and noticed that one in particular was very hot! I immediately switched the computer off
and took a better look. I'd plugged it in upside down. D'oh! You can just about see the mistake in the picture above. It's the top-right IC, and
you can see that the notch drawn on the silkscreen is not matched with a notch on the actual chip.
An interesting property of the 74xx series logic chips is that the ground and +5v connections are at opposite corners, so if you accidentally
plug the chip in backwards it is directly reverse-biased. I don't know if this is helpful because it alerts you to the error quickly, or harmful
because it is likely to damage the chip.</p>
<p>I took the chip out and replaced it with another one (I was worried it might be broken and didn't want to take any chances, although it
turns out the chip still works fine). But the computer still didn't work.</p>
<p><h4>Blunder 2</h4></p>
<p>Nothing else was getting hot, and I couldn't spot any other mistakes, so this had me scratching my head for quite a while.</p>
<p>Eventually I removed the ribbon cable and verified that the computer still worked without the front panel attached. It did.</p>
<p>I then connected signal lines from the bus to the front panel individually using jumper wires, one by one, until the computer
no longer worked, and I discovered that it worked as long as the RD line was not connected to the front panel. I had a good look at the PCB
and still couldn't see any mistakes. All the pins were soldered correctly, and there were no solder bridges.</p>
<p>So then I went back to the schematic to see if I could figure out what was wrong, and realised the mistake almost straight away.
It was the logic error described earlier, where RD was always held low when we're not writing, even when the front panel doesn't have control of the bus. D'oh!</p>
<p>The solution here is to modify the circuit to use a NOR gate and an inverter so that the RD line is left floating when either we're
in writing mode, or we don't have the bus at all. While not all of the gates of all of the chips on the board were in use, it turned
out I had no spare NOR gates and no spare inverters. I really didn't want to have to pay for (and wait for) a new PCB, so I considered
various ways to add a chip to the existing PCB. 
Eventually I settled on supergluing an IC socket to the board, with the pins bent outwards, and then running wires from these
pins to the various places they need to connect to.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2458"><img src="https://img.incoherency.co.uk/2458/thumb"></a></p>
<p>Note the leftmost chip, with the grey wires running to it.</p>
<p>I thought this was quite an elegant fix, all things considered. There are just a handful of bodge wires running around the board to connect
the new chip up to the signals it needs, and I bent out the pin that it needs to drive on the chip that was already there, so that pin is no longer driven
by the offending signal on the PCB.</p>
<p>I connected it back up to the RC2014 and the computer now worked! That was a relief. I soldered up most of the rest of the LEDs and switches,
and found that everything worked. Great success.</p>
<p>The only thing left is to wire up the power switch (easy) and the "busy" light from the CompactFlash module.</p>
<p><h4>Blunder 3</h4></p>
<p>The RC2014 CompactFlash module already has an LED on it to indicate when it is busy, so my plan was to simply break this signal out
to a pin header socket superglued to the card, and then run a wire from the pin header socket over to the pin header on the front panel PCB. There's no resistor for it
on the front panel PCB, so I added that on the CompactFlash module as well.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2459"><img src="https://img.incoherency.co.uk/2459/thumb"></a></p>
<p>I thought this was definitely going to work and couldn't even imagine how it could go wrong. The power to the LED
is just copied over to the front panel. What could be simpler?</p>
<p>Well, I plugged it all in and found that the DISK light on the front panel
stayed lit 100% of the time. It turns out that the LED on the CompactFlash module is switched
on the negative side rather than the positive side, so the positive side is always at 5v. D'oh! I didn't fancy the idea of solving this by dismantling
the front panel assembly and rejigging the soldering on the DISK light, so I instead used the switched-ground
signal on the CF module to switch an S9015 PNP transistor that would then switch a positive supply to the DISK light, and that worked.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2439"><img src="https://img.incoherency.co.uk/2439/thumb"></a></p>
<p>Not as elegant as what I had in mind, but it does the job.</p>
<p><h2>Assembly</h2></p>
<p>The logic PCB attaches to the back of the front panel with 4 long standoffs. They're pieces of hex bar that are threaded to M3
all the way through. Each one has an allen bolt at the front to hold the front panel to the standoff, and an allen bolt at the back to
hold the PCB to the standoff. It's a very quick and easy way to attach flat panels together at a fixed distance.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2433"><img src="https://img.incoherency.co.uk/2433/thumb"></a></p>
<p>To screw the backplane into the case, I removed all of the cards and used the backplane mounting holes as a drilling template
to put 6 holes in the bottom of the case. I then bolted some short standoffs to the bottom of the case, and attached the backplane
to the standoffs with short allen bolts.</p>
<p>An unfortunate consequence of the bus-to-IDC60 break out board is that it essentially takes up 2 backplane slots
just because the ribbon cable sticks out too far to allow access to the adjacent slot. An improvement would be to use
a 90-degree IDC connector so that the ribbon cable plugs straight down instead of from the side.</p>
<p>To get power to the computer I've wired up a panel-mount barrel jack socket to a cable with a pin header socket on the other
end. The pin header socket plugs into a pin header on the logic PCB (with the positive side coloured red so that I don't
install it backwards) and will eventually mount in the back panel of the case.</p>
<p>The USB keyboard input to the VGA serial terminal is in an inconvenient place, so that too has a cable to bring it round to a panel-mount
connector.</p>
<p>The only other connections I need are the VGA connection and the second serial port. Both of these are positioned on cards close to the
back of the computer already, so I'll probably just cut holes in the back panel that are large enough to provide access.</p>
<p>Power supplies have come on quite considerably since the late 70s. Small, cheap, and efficient DC <a href="https://en.wikipedia.org/wiki/Switched-mode_power_supply">switch-mode power
supplies</a> are today so abundant that we don't even notice them, but the Altair 8800 used a power supply that was almost as big as the rest of the computer
put together!</p>
<p><a class="img" href="https://img.incoherency.co.uk/2438"><img src="https://img.incoherency.co.uk/2438/thumb"></a></p>
<p>Not only is such a linear power supply large and expensive, it is also quite inefficient, wasting a lot of power and heat, and necessitating
a large fan to keep it cool.
I considered adding a small fan to the inside of my case, but nothing here gets noticeably warmer than ambient temperature. The fan
would really only be there for sound effects, which doesn't seem worth it.</p>
<p><h2>Usage</h2></p>
<p>I hand-assembled a short program using the <a href="http://clrhome.org/table/">clrhome.org Z80 instruction set table</a> as a reference.
It's a very good presentation of the instruction set, showing all 1-byte opcodes on a single screen, and giving more information
about each one on mouse hover, with multi-byte opcodes further available down the page.</p>
<p>Having generated the machine code, we need to get it into the memory so that the machine can execute it.  </p>
<p>Unfortunately, when my RC2014 is reset, it maps a ROM bank at address 0, and it is not possible, with my front panel, to interrupt
the CPU before it has fetched the first opcode. But the first instruction in the ROM is a jump. The easiest
way I have found to execute a program using the switches is to grab the bus after the CPU has fetched the jump opcode, and then
switch in a RAM bank at address 0, and then toggle in
the destination address for the jump (i.e. write 0003h - but little-endian - to send execution to address 3), followed by the actual code to execute, starting at address 3.
When the bus is released and the CPU continues executing, it has already fetched the jump opcode from address 0 of the ROM, and it
proceeds to fetch the destination address from addresses 1 and 2, which then point to
address 3, and we've hijacked the ROM's jump to instead jump to our own code in RAM.</p>
<p>The bank switching is quite simple, but not obviously documented anywhere. I worked out how to use it by finding the
relevant config in the <a href="https://github.com/wwarthen/RomWBW/blob/8f2754b0f713d6274c9639715fd2411a360bda02/Source/HBIOS/cfg_rcz80.asm#L31">RomWBW source</a>.
You first have to write a 1 to IO port 0x7c to enable paging, followed by writing your bank selection number to IO port 0x78, 0x79, 0x7a, or 0x7b, depending on
which page you want to switch. Each page is 16K long, and can point to one of 32 available ROM banks, or 32 RAM banks. The page for addresses
0000 to 3fff is switched using IO port 0x78. Bank numbers 0 to 31 are ROM, and 32 to 63 are RAM, so to put a RAM bank in the first page, I write a 32 (0x20)
to IO port 0x78. An interesting property of the bank switching is that you can have multiple pages pointing to the same bank at the same time. For example
if you write the same bank number to IO ports 0x78 and 0x79, then every byte in the range 0000-3fff will be the same as the corresponding byte in the range 4000-7fff.</p>
<p>For extended front panel usage, it would be worth removing the 512K ROM/512K RAM card and replacing it with a single RAM chip connected
directly to the bus, with no bank switching logic. That way you'd just toggle in the code starting at address 0 and hit reset.</p>
<p>I originally wanted to narrate the video demonstration to explain what
I'm doing, but I felt quite strange sitting on my own narrating my actions, so I stayed quiet and added textual annotations
instead. They're probably more useful anyway.</p>
<p><a href="https://youtube.com/watch?v=q5BEHFvPDhc"><img src="https://img.incoherency.co.uk/2437"></a>
<ul>
<li><a href="https://www.youtube.com/watch?v=q5BEHFvPDhc">Programming the RC2014 using the front panel</a></li>
</ul></p>
<p>At about 1m28s in the video you might notice that the A1 light flickers while I'm not touching the switch. The toggle switch on the A1 line is a little bit flakey,
but it seems to be getting better with use so I expect it just needs to wear in a little bit. At any rate, it's not bad enough to
be worth dismantling the whole thing and replacing the switch.</p>
<p>Having to manually toggle in every single address is much more work than I anticipated. I can certainly see why most front-panel-oriented
computers have an auto-increment feature for the address.</p>
<p>Something I wasn't sure about was whether it is safe to switch the clock speed selection jumper while the computer is running, if the
CPU is blocked on either BUSRQ or WAIT (from single-stepping). I tried it and it works fine, which is quite handy.</p>
<p>Anyway, that's all I have to say about my front panel project. I learnt a lot about electronics and computers, and enjoyed the process. Please email me if
there's more you want to know about it, or if you're thinking of making your own front panel.</p>
<p><h2>More</h2></p>
<p>I still need to make some holes in the back panel of the case to
mount a power socket and USB keyboard socket on, and allow access to the VGA and serial ports.</p>
<p>I'm planning to eventually be able to use the serial port for <a href="https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol">SLIP</a> networking.
I have a basic ping test working in CP/M, but nothing more.
It takes 900ms to reply to ping, or 80ms if debugging prints are removed. I'm writing the code in
<a href="https://techtinkering.com/2008/10/21/installing-zde-1-6-a-programmers-editor-for-cpm/">ZDE 1.6</a> which is not good but is better than
ED. And I'm using the <a href="https://techtinkering.com/2008/10/22/installing-the-hi-tech-z80-c-compiler-for-cpm/">Hi-Tech C compiler</a> to compile it.
The Hi-Tech C compiler is seriously old. Hailing from 1987, it pre-dates even C89!</p>
<p>I'd like to find a better text editor. ZDE is much better than ED, but it still sucks. <a href="http://cowlark.com/">David Given</a> wrote a <a href="http://cowlark.com/2019-06-28-cpm-vi/">vi
implementation for CP/M</a> in a 9-hour live stream, but it is targeted at his Kaypro II terminal and I tried it briefly but it didn't quite work right with the RC2014 VGA serial terminal, so
I think it would need some modification.</p>
<p>Another thing I'd like to make is a basic sound card. There are a handful available for the RC2014 using commercial sound chips, but I'd like to do it from first
principles instead. It would probably just be able to output a single tone, like a PC speaker, rather than arbitrary sounds like a proper sound card. For example using some glue logic
to let the software write a frequency selection into an IO port, which then controls a square wave generator circuit of some sort. You could conceivably
include more than one on the same card (at different IO ports) to allow multiple simultaneous tones.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/rc2014-frontpanel.html</link>
   <guid>http://incoherency.co.uk/blog/stories/rc2014-frontpanel.html</guid>
   <pubDate>Tue, 12 Nov 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The RC2014 Z80 Microcomputer</title>
   <description><![CDATA[I recently came across the RC2014. It is a simple computer sold in kit form, and using a Zilog Z80 CPU.]]></description>
   <content:encoded><![CDATA[<p>I recently came across the <a href="https://rc2014.co.uk/">RC2014</a>. It is a simple computer sold in kit form, and using a Zilog Z80 CPU.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2412"><img src="https://img.incoherency.co.uk/2412/thumb"></a></p>
<p>I understand that 2014 is the year it was designed, and "RC" stands for "retro computer".</p>
<p><h2>What is it?</h2></p>
<p>The RC2014 website says:</p>
<p><blockquote>RC2014 is a simple 8 bit Z80 based modular computer originally built
to run Microsoft BASIC. It is inspired by the home built computers of the late 70s
and computer revolution of the early 80s. It is not a clone of anything specific,
but there are suggestions of the ZX81, UK101, S100, Superboard II and Apple I in
here. It nominally has 8K ROM, 32K RAM, runs at 7.3728MHz and communicates over
serial at 115,200 baud.</blockquote></p>
<p>Being a "modular" computer means that the RC2014 uses a <a href="https://en.wikipedia.org/wiki/Backplane">backplane</a>
system that various modules can be plugged into. A backplane is essentially a motherboard
that has no components on it: all it does is connect the modules together. The CPU
has no special place, it's just another module connected to the bus. I have found playing with the RC2014 has
given me a much better understanding of how a CPU actually interacts with the other
elements of a computer.</p>
<p>For convenience of hobbyist use, the RC2014 uses 0.1" pin headers to plug into the backplane,
rather than the more common <a href="https://en.wikipedia.org/wiki/Edge_connector">card edge connector</a>
used by S-100, ISA, PCI, etc.</p>
<p>The standard backplane has 40 pins, of which 4 are unassigned and can be used for whatever you want.
The "enhanced" backplane has an additional 20 pins, incorporating a handful of CPU lines that were missing
from the original bus, an additional 8 pins of data bus for potential expansion to 16-bit CPUs, and 4
more unassigned pins.</p>
<p>As far as I'm aware, it's not possible to buy a fully-assembled RC2014, they are only available in kit form.</p>
<p><h2>Building the kit</h2></p>
<p>The RC2014 kits, and various upgrade modules, are available from the <a href="https://www.tindie.com/stores/semachthemonkey/">RFC2795 Ltd Tindie Store</a>,
and there are also various other modules available from other sellers, including "single-board computer" variants, a video card,
various storage modules, and also other CPU options, including the Z180 and the 6502.</p>
<p>I chose the all-singing all-dancing "Zed Pro" variant of the official kit, which comes with
a 12-slot "enhanced" backplane, 512K ROM, 512K RAM, dual clocks, and dual serial ports.</p>
<p>It's quite a bear to solder up. Even though not all of the "enhanced" slots have the headers installed, the backplane sockets
alone are 5*60 + 7*40 = 580 solder joints. Then you have a corresponding 40+ pins per card for the backplane plug,
40 pins each for CPU, ROM, RAM, and serial controller, and 13 other 14- and 16-pin ICs. That's already over 1000 pins,
and there are more headers, resistors, capacitors, etc. still to count. It took me many hours over 2 sittings to
finish soldering up what I've got so far. And I still have more to acquire!</p>
<p>If you're playing along at home, I'd recommend taking the time to make sure the pin headers and IC sockets are properly seated against the board.
I like to solder just one pin at first, and then push the part down with my finger while I re-melt the solder, to make sure it sits nice
and flat. If you solder all 40 pins and then decide you don't like the angle it's mounted at, you'll have a tough job fixing it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2413"><img src="https://img.incoherency.co.uk/2413/thumb"></a></p>
<p>When I'd finished, I only had 1 resistor left over, and the machine seems to run OK so it can't have been an important one.</p>
<p>With the parts assembled, it's just a case of plugging a USB FTDI cable into a serial port header, switching the machine on,
hitting the reset button, and then interacting with it over the USB serial cable. I understand that the dual clock module
has a power-on reset function, so that it can automatically reset the CPU when power is applied, but I am not entirely sure
how it is meant to work, or whether I have not enabled it, so for now I need to manually reset it every time I switch it on.</p>
<p><h2>Memory</h2></p>
<p>The Z80 has a 16-bit address bus and therefore only 64K of address space, so what's the use in having 512K of RAM?</p>
<p>It is possible to use <a href="https://en.wikipedia.org/wiki/Bank_switching">bank switching</a> to map
different parts of the 512K into the 64K address space at any given time. Note that this is not
a CPU feature! The CPU neither knows nor cares about the memory layout. The CPU just puts addresses on the
bus and the memory hardware does whatever it wants. The software tells the memory hardware to change the
bank by writing to an I/O port. On the RC2014, this is implemented with just 5 TTL chips.</p>
<p>I couldn't find a schematic or explanation for the "official" RC2014 bank switching, but <a href="http://www.smbaker.com/z80-retrocomputing-11-cpm-on-the-rc2014">Scott
Baker's blog</a> has a well-documented example of a bank-switching implementation (as well as many other excellent RC2014-related resources):</p>
<p><blockquote>Writing to the bank select port clocks D0 and D1 into a pair of flipflops
on a 74HC84N. The RC2014’s RESET pin is connected to the clear pin of the flipflops,
so that a reset will always reset the flipflops back to zero. This allows us to write
any of four values — 0, 1, 2, or 3 — to the flipflops and will serve as our bank
select. The default is zero.</blockquote></p>
<p>(D0 and D1 are the least significant bits of the data bus).</p>
<p>The 512K ROM module came with <a href="https://github.com/wwarthen/RomWBW">RomWBW</a> flashed on it. RomWBW includes
a built-in boot monitor, as well as a bundled copy of CP/M. When booting CP/M from RomWBW, it comes up with
a 384K RAM disk and a 384K ROM disk with some useful programs on it. RomWBW is quite a convenient way to get a
working CP/M system without needing a "real" storage device.</p>
<p><h2>CP/M</h2></p>
<p>CP/M is an extremely simple operating system. It only has support for single-tasking, and while your program is running it has complete
control of the entire machine.</p>
<p>There is a great page about CP/M Internals on the <a href="https://obsolescence.wixsite.com/obsolescence/cpm-internals">Obsolescence Guaranteed</a> website, but
the summary is that the OS is composed of the BIOS (basic input/output system), BDOS (basic disk operating system), and CCP (console command processor).
The BIOS has to be customised to match the hardware, and present a standardised view of it to the rest of the system. The BDOS provides higher-level functions
for file manipulation, and the CCP provides a user interface. When a program is executed using the CCP, it is loaded into the TPA (transient program area),
starting at 0x100 (256 bytes), and then executes from there. The lower 256 bytes include <a href="https://en.wikipedia.org/wiki/Branch_table">jump vectors</a>
to access the BDOS and BIOS functions,
as well as the contents of the command line arguments and various other stuff that wants to be at a standardised address. The BIOS, BDOS, and CCP live at the top of memory,
so that the large chunk in the middle is available for the TPA. There is a total of <a href="http://www.gaby.de/cpm/manuals/archive/cpm22htm/ch5.htm#Section_5.6">41
system calls</a>.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2414"><img src="https://img.incoherency.co.uk/2414/thumb"></a></p>
<p>The standard CP/M text editor is called ED. It seems to work a little bit like the eponymous Unix text editor, but with different syntax. I still haven't quite got
a good mental model of how to correctly use it, but I've got to the point where I can stick some characters in a file in the order I desire, and then rearrange
them later. But I still find the editor very clunky, and I'd like to get better at using it.</p>
<p>Having written an assembly language program in ED and stored it in the RAM disk at (say) A:HELLO.ASM, we need to assemble it using the ASM program.
I followed <a href="https://jefftranter.blogspot.com/2014/03/using-cpm-assembler.html">Jeff Tranter's instructions</a> and got my hello world program assembled.
The ASM program produces HELLO.PRN and HELLO.HEX files, but surprisingly does not produce HELLO.COM which is the one we'd want if we wanted to execute
the program. I don't know why. HELLO.PRN contains our original assembly language source code, but annotated on the left hand side with a hex listing of the
generated machine code. HELLO.HEX contains the generated machine code in <a href="https://en.wikipedia.org/wiki/Intel_HEX">Intel HEX</a> format.</p>
<p>Since we actually do want to execute the program, we need to get hold of HELLO.COM. Fortunately, the LOAD program can do this for us. LOAD reads the HELLO.HEX file and
produces HELLO.COM, which we can then execute.</p>
<p>Another interesting program is SAVE, which is used to save the contents of the TPA to the disk. I'm not quite sure when you'd want to do this, but you can do
some funny things with it. For example if you write a program in MBASIC, and then return to the CCP, you can save the contents of the TPA to disk in a new
.COM file, and then when you execute that new .COM file, you'll be back in MBASIC, but your BASIC source code will be in memory already, because it was in the
memory that you saved. Presumably this won't work against anything that dynamically initialises its memory contents when it starts up.</p>
<p>There is lots of documentation available in the <a href="http://www.gaby.de/cpm/manuals/archive/cpm22htm/index.htm">CP/M manual</a>, but much of it is confusing.</p>
<p>I originally got the 512K RAM module so that I'd have a chance of running <a href="https://github.com/EtchedPixels/FUZIX">FUZIX</a>, a Unix-like OS for 8-bit computers.
FUZIX uses bank switching to provide context switching, with one process per bank of memory. I initially looked down on CP/M as a primitive and uninteresting
operating system, but it's actually fun to learn about such a simple way of working, and I'm enjoying CP/M so much that I probably won't bother with
FUZIX for a little while.</p>
<p><h2>VGA Console</h2></p>
<p>Having to use the RC2014 over an FTDI cable connected to a modern computer weakens the experience somewhat. From the user perspective, it's no different
to simply running CP/M in an emulator. For that reason I want to get the RC2014 to talk to a keyboard and a display itself.
The serial ports are exposed on the backplane, so it's quite easy to plug in another card that can provide a serial terminal, without
any software changes required.</p>
<p>The recommended way to do this is to use a <a href="https://www.tindie.com/products/semachthemonkey/raspberry-pi-zero-serial-terminal-for-rc2014/">Raspberry Pi Zero</a> card, mounted in
one of the backplane slots, to provide a serial terminal.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2406"><img src="https://img.incoherency.co.uk/2406/thumb"></a></p>
<p>But that idea didn't really satisfy me. A Raspberry Pi is a computer in its own right, and is substantially more powerful than an RC2014. It still feels a bit too close to just using an emulator.</p>
<p>My favourite option is Marco Maccaferri's <a href="https://www.tindie.com/products/maccasoft/vga-serial-terminal-kit-for-rc2014/">VGA serial terminal</a>.
It takes a USB keyboard for input and provides an 80x25 character console on the VGA output, using a <a href="https://en.wikipedia.org/wiki/Parallax_Propeller">Parallax Propeller</a> microcontroller. Now, granted,
a Parallax Propeller is <i>also</i> substantially more powerful than an RC2014, but importantly
it <i>isn't</i> a computer, and it comes in a through-hole package so it doesn't spoil the aesthetic.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2407"><img src="https://img.incoherency.co.uk/2407/thumb"></a></p>
<p>Unfortunately, Marco's VGA serial terminal was out of stock when I wanted to get one, so I tried to recreate it using an Arduino. I'd already seen Ben Eater's
<a href="https://www.youtube.com/watch?v=l7rce6IQDWs">World's Worst Video Card</a> project, so I understood that it was possible to bit-bang a VGA signal,
and I found Sandro Maffiodo's <a href="https://github.com/smaffer/vgax">VGAX</a> library already implemented all the hard parts. Unfortunately, the
Arduino is not really fast enough, so the library only allows for 120 pixels of horizontal resolution.</p>
<p>Also, the framebuffer at 120x60 and 2 bits-per-pixel takes up 1800 bytes of RAM. The Arduino only has 2048 bytes in total, and that doesn't leave enough remaining for
the character buffer and stack variables. But I only needed black and white, so I modified
the library to only use 1 bit per pixel, and <a href="https://gist.github.com/jes/1d561d4a034c841a083ce80d4520e27f">managed to get it working</a> as a 19x10 character display:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2404"><img src="https://img.incoherency.co.uk/2404/thumb"></a></p>
<p>The wiring is remarkably simple. 3 pins of the Arduino are connected through resistors to 3 pins of the VGA plug on the screen (hsync, vsync, and the green channel), and the TX line from
the RC2014 bus is connected to the RX pin of the Arduino, so that the Arduino reads the serial output from the RC2014.</p>
<p>But 19x10 characters is really not enough to be going on with, and I'd still have to figure out how to provide keyboard input. And thankfully
Marco's VGA serial terminal is back in stock and I now have one on order, so I won't have to bother.</p>
<p><h2>Front Panel</h2></p>
<p>One of the coolest parts about old computers was the <a href="https://en.wikipedia.org/wiki/Front_panel">front panel</a>. Two iconic examples include the Altair 8800 and IMSAI 8080:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2409"><img src="https://img.incoherency.co.uk/2409/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/2408"><img src="https://img.incoherency.co.uk/2408/thumb"></a></p>
<p>The switches and lights on the front panel act as a crude debugger, allowing the user to pause execution, single step through instructions, and view and alter the contents
of memory. Additionally, on machines with no ROM, the front panel is the only way to get any code to execute after a cold boot, even if it's just a minimal bootloader for an OS on disk.</p>
<p>So I want to make a front panel for the RC2014.</p>
<p>As it happens there's an excellent article in the <a href="https://ia801201.us.archive.org/31/items/Kilobaud197806/Kilobaud%201978-06.pdf">June 1978</a> issue of <a href="https://archive.org/details/kilobaudmagazine">Kilobaud Magazine</a> on just such a project: "Home-Brew Z-80 System Part 1: front-panel construction". It's about how to make a homemade front panel
for a Z80 on an S-100 bus, but it's not too far away from an RC2014. I'm not quite good enough at electronics to understand how it works yet,
but I think it should be doable.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2411"><img src="https://img.incoherency.co.uk/2411/thumb"></a></p>
<p>Another good example of a homemade front panel is the one on the <a href="http://homebrewcpu.com/">Magic-1 Homebrew CPU</a>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2410"><img src="https://img.incoherency.co.uk/2410/thumb"></a></p>
<p><h2>Storage and networking</h2></p>
<p>I'd obviously like to get some sort of permanent storage. A CompactFlash card is the cheap and easy option, but a more authentic experience would be dual floppy drives.</p>
<p>And I'd like to find a way to get this thing connected to the Internet, and maybe host a small website on it. <a href="https://www.grahamedgecombe.com/">Graham</a> suggested
using <a href="https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol">SLIP</a> to connect it to another computer over the second serial port, which is probably
the easiest way to go. Another option would be to use a <a href="https://www.wizse.com/w5500s2e/">WIZnet W5500S2E-R1</a> ethernet module or similar, and do away with the requirement for
a "host" computer.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/rc2014.html</link>
   <guid>http://incoherency.co.uk/blog/stories/rc2014.html</guid>
   <pubDate>Mon, 21 Oct 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>My Arduino-based industrial process controller</title>
   <description><![CDATA[For my 3d metal printing project, I need the sintering furnace to stick to a pre-defined temperature
profile. Unfortunately, the controller that my furnace came with only allows you to set a constant temperature. It maintains
a constant temperature very well, but the operator frequently has to manually update the temperature in order to stick to the defined profile.]]></description>
   <content:encoded><![CDATA[<p>For my <a href="https://incoherency.co.uk/blog/stories/metal-3d-printing-first-results.html">3d metal printing project</a>, I need the sintering furnace to stick to a pre-defined temperature
profile. Unfortunately, the controller that my furnace came with only allows you to set a constant temperature. It maintains
a constant temperature very well, but the operator frequently has to manually update the temperature in order to stick to the defined profile.</p>
<p>TL;DR is I ended up making an Arduino-based industrial process controller with custom PCBs and a 3d-printed case:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2363"><img src="https://img.incoherency.co.uk/2363/thumb"></a></p>
<p><h3>CAL 9500</h3></p>
<p>I first bought a secondhand CAL 9500 (left) to replace the REX-C100 (right) that the furnace came with.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2345"><img src="https://img.incoherency.co.uk/2345/thumb"></a></p>
<p>This is a <i>process controller</i>, which means that in addition to setting a constant temperature, it
allows you to program in a profile for how you want the temperature to change over time. I wired the CAL 9500 into my furnace, and I was just starting to figure
out how the menu system works and how to program it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2348"><img src="https://img.incoherency.co.uk/2348/thumb"></a></p>
<p>I noticed that the device was getting quite warm but didn't think too much of it. Eventually it fizzed
and then banged and then the magic smoke came out and it didn't work any more. I think I was sold a pup.</p>
<p>But from what I saw of the CAL 9500, I didn't like it. The way the wires are attached to the back, combined with the poor access inside the chassis of the furnace,
means it is impossible to fit the controller in the front panel if the wires are already attached, but it is also impossible to attach the wires if the controller is
already in place. To solve this I hacked a slot out of the bottom of the front panel so that I could connect the wires and then slide the controller in (hence
the gaffa tape in the photo above), but I now wish I hadn't. I also found the small buttons were hard to press and hurt the ends of my fingers, which is doubly
problematic as the interface in many places requires you to hold down 2 buttons for several seconds at a time. And finally, it is impossible to find anything
in the interface without consulting the manual, and even then it is hard to understand.</p>
<p><h3>Arduino</h3></p>
<p>A new CAL 9500 is over &pound;200, which I'm not interested in spending. The seller of the secondhand one said they'd send me another, but they still haven't.
So my next idea was to build my own process controller using an Arduino Nano. I used 4 buttons instead of 3 so that "chording" wouldn't be necessary, and I used
an OLED screen instead of 7-segment displays so that the screen can display enough text to make the interface understandable. Then I used a MAX31855 breakout
board to interpret the signal
from the thermocouple, and a solid-state relay to switch the furnace relay on and off.</p>
<p>The OLED screen is an SH1106, which is almost the same, but not quite the same, as the much-more-common SSD1306. The protocol is different enough that
you need to go out of your way to find a library that supports it, but similar enough that the library is still just called "ssd1306". If you try
to drive an SH1106 as if it's an SSD1306 then only the top 8 rows of pixels work, leading you to believe that the screen is broken. That took me a while to figure out.
The screen is driven over <a href="https://en.wikipedia.org/wiki/Serial_Peripheral_Interface">SPI</a>.</p>
<p>The MAX31855 is also driven over SPI, and the solid-state relay just needs 1 pin to switch it on/off.</p>
<p>The Arduino program ended up surprisingly complicated, and most of it is just spaghetti code to implement the menu system.
The code is
<a href="https://github.com/jes/jpc1000/blob/master/jpc1000.ino">on github</a>. I ended up limiting the maximum number of program segments to
only 16, because the Arduino only has 2KB of RAM, and I was using too much. It would be possible to cut the memory usage down by, for example,
removing the unused fonts from the ssd1306 library, and allocating fewer static arrays for each program segment, but I think
16 will do me for now.</p>
<p>But it's 2019, and even the Arduino Nano isn't <i>that</i> small. I shouldn't have to worry about fitting my program inside 2KB! It seems like there should be
something in the same form factor as the Arduino Nano, but with substantially more memory and CPU power. Probably there is.</p>
<p>Each program segment has a type, a target temperature, and a duration. The type is either "step" or "ramp". A "step" segment sets the temperature setpoint
to its target temperature immediately, and then holds it there for the duration of the segment. A "ramp" segment ramps the setpoint linearly from wherever it was
at the start of the segment to the target temperature, over the course of its duration. You build up a temperature profile by chaining together these
"step" and "ramp" segments.</p>
<p><h3>Breadboard</h3></p>
<p>Here is the first working version, wired up on a breadboard:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2350"><img src="https://img.incoherency.co.uk/2350/thumb"></a></p>
<p>(I didn't have enough buttons on hand at this point, so the red button is the "OK" button, and all other inputs are conveyed by connecting/disconnecting jumper
wires).</p>
<p>If you zoom in, you may notice a spurious resistor next to the solid-state relay. The Omron G3MB-202P solid-state relay has "zero-crossing"
behaviour, which means that, when you ask it to switch off, it only actually switches off when the load voltage crosses 0 volts. The idea here is to reduce back-EMF or something
when switching AC loads, not entirely sure. But the problem is that the relay inside the furnace that actually switches the coil on and off also seems
to have some electronic control, which means the "load" applied to my solid-state relay draws almost no current at all. That means the solid-state relay
can't actually tell when the load voltage has crossed 0 volts, so it just switches the load on and never switches it off. Disaster! Adding a 10 kOhm resistor
in series with the load makes it draw enough current so that the solid-state relay switches off when you want it to. Or, at least, that's my best guess at what
is going on.</p>
<p><h3>PCBs</h3></p>
<p>Normally at this point I would build the project up on prototyping board and then call it done, but this time I wanted to be a bit more professional, so
I designed some PCBs using <a href="http://kicad.org/">KiCad</a>. The user interface is quite hard to understand at first, I recommend the
<a href="https://www.youtube.com/watch?v=JN_Y93RTdSo&list=PLy2022BX6Eso532xqrUxDT1u2p4VVsg-q">Getting To Blinky</a> playlist on the Contextual Electronics
YouTube channel, although note that some of the key bindings seem to have changed between KiCad 4 and 5, so you'll have to figure that out on your own.</p>
<p>To make the project fit neatly in the "1/16 DIN" panel mount available on the furnace, I decided to split it across two PCBs. One PCB would be mounted vertically
and contain the OLED Screen and 4 buttons, and the other PCB would mount horizontally, inside the chassis, and contain the power supply, Arduino, and solid-state
relay.</p>
<p>To make each PCB, you first draw the schematic in the "Eeschema" part of KiCad:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2360"><img src="https://img.incoherency.co.uk/2360/thumb"></a></p>
<p>and then you draw the actual PCB layout using "Pcbnew", while KiCad automatically makes sure that you don't connect things that shouldn't be connected, and you do
connect things that should be connected:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2361"><img src="https://img.incoherency.co.uk/2361/thumb"></a></p>
<p>Laying out the PCB is a surprisingly fun task, it's almost like a puzzle game.</p>
<p>This is a 2-sided PCB, and
the holes for the component legs are "plated through holes" which means the component legs are electrically
connected to the copper on both sides of the board. This is useful as it means you can run traces between components on either side of the board, which means
traces can "overlap" each other without you having to solder in wires to jump them over one another. Another cool feature of 2-sided PCBs is "vias". A "via"
is just a plated through hole that you don't solder any component leg to! This creates a connection through the middle of the PCB that connects
the top side to the bottom side, such that you can route a trace somewhere on the board, then drop it down to the other side through a via, and then
continue routing on the other side. This makes routing the final few traces much easier, when the board is already populated with other traces that are
getting in the way.</p>
<p>Having laid out the PCB, you need to generate <a href="https://en.wikipedia.org/wiki/Gerber_format">"Gerber"</a> and "drill" files in order to get it manufactured. The drill files obviously just describe where
(and in what size) holes need to be drilled on the board. The Gerber files are instructions for a plotter that
describe what is on the different layers of the board. There is more than just "copper or not copper", there is also a "solder mask" layer for each side, which
is the stuff that actually
gives PCBs their colour: solder mask is a layer applied above everywhere that you don't want to solder, to prevent solder from spreading along the traces and
covering the entire board. It also prevents metal items that touch the circuit board from shorting out the traces. There is also a "silk screen" layer for each side,
which lets you put writing and graphics on top of the solder mask, although I understand that if you are only having a small number of boards made, the
manufacturers tend to apply this with an inkjet printer rather than make an actual silk screen.</p>
<p>There are many companies that will take Gerber and drill files and manufacture you a PCB, extremely cheaply. I used <a href="https://jlcpcb.com/">JLCPCB</a>, because
they sponsored some of the electronics YouTube videos that I watched. You can watch <a href="https://www.youtube.com/watch?v=ljOoGyCso8s">a tour of the JLCPCB
factory</a> on YouTube, it is very interesting. In total I was charged about &pound;15, for which I got 5 copies (the minimum order quantity) of each of my 2 PCB
designs, delivered to my door, from China, in under a week. What a world we live in.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2362"><img src="https://img.incoherency.co.uk/2362/thumb"></a></p>
<p>While soldering the components on to the boards I realised that I had 2 of the pads swapped for the solid-state relay, which means the Arduino wouldn't be
able to switch it on and off. That's annoying. I also had forgotten to include the resistor that makes the solid-state relay able to switch the load. I solved
both of these problems by connecting the solid-state relay to the PCB with "bodge wires", although unfortunately I don't have any photographs of this and it's now
tucked away inside the furnace chassis so you'll just have to imagine.</p>
<p>With the boards soldered up (modulo the solid-state relay, because I was still working out what to do about it at this point), they can be plugged together
via an 11-pin right-angle header:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2354"><img src="https://img.incoherency.co.uk/2354/thumb"></a></p>
<p>The big black box is the power supply. There are 2 screw terminals for the AC power, 2 that get connected/disconnected by the solid-state relay, and 2 (small)
for the thermocouple.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2353"><img src="https://img.incoherency.co.uk/2353/thumb"></a></p>
<p>So far I have done 2 sinters with this device. On the first one I had some trouble with the power supply, as I was still running it on the breadboard and powering
it off a laptop, but the second one used the power supply on the PCB and worked flawlessly for the whole 12 hours.</p>
<p>The improvement of the process controller over manual control is not only that I no longer have to waste loads of time updating the temperature setpoint, but also
the setpoint is tracked much more accurately. Here is the temperature profile that I managed when updating it manually, compared to what the process controller
managed:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2338"><img src="https://img.incoherency.co.uk/2338/thumb"></a></p>
<p>vs</p>
<p><a class="img" href="https://img.incoherency.co.uk/2364"><img src="https://img.incoherency.co.uk/2364/thumb"></a></p>
<p>(Again, sorry, no axis labels. Gnumeric makes this hard. X is time, Y is temperature in &deg;C, pink line is desired temperature, blue line is measured temperature).</p>
<p>The process controller got almost every datapoint within 1&deg;C of the target. The only time it didn't do this was the initial overshoot after the step up to 150&deg;C
at the very start, which notably is also improved compared to when the furnace was controlled by the REX-C100.</p>
<p><h3>Plastic case</h3></p>
<p>Obviously the only thing left to do is a 3d-printed plastic case.</p>
<p>It's likely that I'll want to reprogram the Arduino at some point, so I need the front panel PCB to be removable in order to gain access to the USB port. To
this end, I made the plastic case in 2 parts: one part holds the main board to the panel on the furnace, and the other part is a neat cover for the front panel
PCB.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2357"><img src="https://img.incoherency.co.uk/2357/thumb"></a></p>
<p>The main board is held in a piece of plastic by some slots and a single screw, and then the plastic piece is held in the furnace by a thin plastic piece that
screws on to it, with the metal panel sandwiched between the two:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2356"><img src="https://img.incoherency.co.uk/2356/thumb"></a></p>
<p>The front panel PCB can be plugged in and unplugged at will:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2355"><img src="https://img.incoherency.co.uk/2355/thumb"></a></p>
<p>And finally I made a case to house the front panel PCB, which is screwed inside the plastic.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2363"><img src="https://img.incoherency.co.uk/2363/thumb"></a></p>
<p>The button caps are connected to each other by thin strings of plastic to
stop them from falling out, but the strings are thin enough to be flexible so that the buttons can all be operated independently. The writing, and the icons
on the buttons, are printed in the same colour as the rest of the case, but raised up slightly, so that they can easily be coloured by rubbing across the
top with a permanent marker.</p>
<p>The device is named by an obligatory series of inscrutable letters, and an impressively-large number, so that it can take its rightful place among the REX-C100s
and CAL 9500s of the world.</p>
<p>So that's the story of my industrial process controller. It was a bit of a distraction from what I was meant to be doing (i.e. the actual task of sintering
3d printed metal parts), but it was fun and I learnt a lot. And if you happen to want to build one just like mine, I can offer free PCBs to up to
4 lucky readers!
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/process-controller.html</link>
   <guid>http://incoherency.co.uk/blog/stories/process-controller.html</guid>
   <pubDate>Sun, 01 Sep 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Home 3d metal printing: first results</title>
   <description><![CDATA[A couple of weeks ago I learnt about an interesting 3d metal printing process,
from a company selling it for $100k USD, and speculated that it might be DIY-able for much less. Well I now have some
promising first results.]]></description>
   <content:encoded><![CDATA[<p>A couple of weeks ago I learnt about <a href="https://incoherency.co.uk/blog/stories/metal-3d-printing.html">an interesting 3d metal printing process</a>,
from a company selling it for $100k USD, and speculated that it might be DIY-able for much less. Well I now have some
promising first results.</p>
<p>TL;DR is that the one on the right here is 3d printed using bronze-filled filament and then sintered into a solid (ish) metal part:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2332"><img src="https://img.incoherency.co.uk/2332/thumb"></a></p>
<p>The model I'm testing with is a 10mm hex socket with 1/4-inch square drive.</p>
<p><h3>Planning</h3></p>
<p>After I wrote the other post on 3d metal printing, <tt>u407</tt> on reddit directed me to <a href="https://www.thevirtualfoundry.com/">The Virtual Foundry</a>.
The Virtual Foundry is an American company that sells metal-filled filaments and describes <a href="https://www.thevirtualfoundry.com/help">a process for sintering
them</a> into solid metal parts. In particular, they describe a process for sintering copper and bronze filaments that does not require the furnace to be under
vacuum. This is good, because this is getting approachable. Interestingly, they combine the debinding and sintering into one continuous firing in the furnace, i.e.
the binder is removed by burning it off in the same furnace as the remaining metal is sintered.</p>
<p>I watched <a href="https://www.youtube.com/watch?v=VJRd0zTegAU">a video from ProjectTube</a> where he tries out The Virtual Foundry copper and bronze
and tries to sinter them, with mixed success. Although, he didn't follow the instructions very closely, and it looks like the furnace he used doesn't
hold its temperature very precisely anyway, so hopefully I can do better.</p>
<p>The Virtual Foundry's bronze filament is reportedly "around 87% metal", with a PLA binder. But it ships from the US which I don't want to wait for, so instead I bought
some <a href="https://shop.3dfilaprint.com/filaprint-metal-bronze-pla-175mm-500gms-12626-p.asp">80% bronze PLA from 3dfilaprint</a>, which is much cheaper, and
ships from the UK, but doesn't come with any promises about sintering.</p>
<p>I also contacted BASF about their <a href="https://www.basf.com/global/en/who-we-are/organization/locations/europe/german-companies/basf-3d-printing-solutions-gmbh/metal-solutions/Ultrafuse_316L.html">Ultrafuse 316L</a> filament. They don't really seem setup to deal with hobbyists, but they eventually sent me the "User Guidelines"
for the Ultrafuse material, and I discovered that it requires a catalytic debind process. That is not something that I'm likely to be able to do. But they also
said that if I 3d print some parts in their filament, I can ship them to BASF and they'll debind and sinter the parts for €40/kg (plus shipping and VAT, I assume).
That might still end up being cheaper
than getting stuff 3d printed in metal by Shapeways, but I'm not really interested in having third-parties make the parts for me, I want to be able to do it myself.
It would be great to be able to do steel eventually, but getting bronze working is a good place to start.</p>
<p><h3>Printing</h3></p>
<p>Figuring out how to print this stuff took a little work. My first attempt was to just load the filament into the printer (I'm using an Anycubic i3 Mega) and print it with the same settings I use for
ordinary PLA. This didn't work. The nozzle oozed filament a lot more than it normally does, I think because the bronze filament conducts heat more readily,
so there is more molten filament inside the hot end. But that's not a problem, that won't stop it printing. The reason it didn't print is that the filament was getting
balled up inside the extruder and not going down the Bowden tube. I have <a href="https://www.youtube.com/watch?v=ubnYH5s1Q5k">a video demonstrating the problem</a>.</p>
<p>The pieces of filament that I removed while debugging this problem looked like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2334"><img src="https://img.incoherency.co.uk/2334/thumb"></a></p>
<p>You can see that the gear on the extruder has eaten into the filament quite a lot, and they have some sharp bends in. I tried again with the speed reduced to 50% and the same thing happened.
Eventually I figured out that repeated retraction was wearing out the filament, as
it was run back and forth over the gear in the same spot. So I printed it again with retraction turned off, and the print completed, even with the speed raised back to
100%:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2335"><img src="https://img.incoherency.co.uk/2335/thumb"></a></p>
<p>(I know it looks a different colour here, but it's just different lighting)</p>
<p>The stringing between the parts is a combination of the ooziness of the nozzle, and the lack of retraction. But it's not too hard to clean it up with a knife, this
filament is surprisingly much softer than plain PLA is, and cuts more easily.</p>
<p><h3>Sintering</h3></p>
<p>The Virtual Foundry sintering process for bronze needs a furnace that can reach 865&deg;C. I picked up this one for less than &pound;200:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2336"><img src="https://img.incoherency.co.uk/2336/thumb"></a></p>
<p>It has a PID controller to keep the temperature at whatever you set it to, with a maximum of 1150&deg;C, and even comes with a graphite crucible, which would
be useful if I ever do any casting.
The main thing wrong with it is that the chamber is quite small.</p>
<p>The other thing required is some "magic black powder" that TVF sell for $17/kg. They don't say what is in it, but here's what we do know:</p>
<p><ul>
<li>it sets solid after mixing with water</li>
<li>it is slightly porous, to allow PLA gases to escape</li>
<li>despite being porous to gases, it prevents oxygen from getting in</li>
<li>it turns white from the outside-in as it uses up oxygen</li>
</ul></p>
<p>With that in mind, I surmised that a mixture of "fine casting plaster" and charcoal powder would do the job. Casting plaster sets solid when mixed with water, and is
porous to gases, and charcoal burns
when exposed to oxygen and heat, and turns white after burning, so what could go wrong? So I smashed up a bunch of charcoal, seived out the powder, and mixed it with
my plaster roughly 50:50 by weight:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2337"><img src="https://img.incoherency.co.uk/2337/thumb"></a></p>
<p>I coated my "green part" in this charcoal plaster, inside a piece of metal tube, and left it to set.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2305"><img src="https://img.incoherency.co.uk/2305/thumb"></a></p>
<p>If this is indeed the makeup of the TVF Magic Black Powder, then they are using much finer charcoal powder than I managed to make, as you can clearly see the white
spots and black spots, instead of a smooth grey colour.</p>
<p>The TVF sintering process takes almost 12 hours. But most of this is at temperatures far too low to sinter bronze, so I suspect it is mostly dedicated to boiling/burning off the PLA and
driving the remaining moisture out of the plaster, so it's plausible that you could stop partway through and then resume another day,
but for my first attempt I wanted to follow their instructions as closely as possible.</p>
<p>Yesterday I had 12 uninterrupted hours in which to supervise the furnace, so yesterday I did my sintering. I kept quite a detailed log of the temperatures:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2338"><img src="https://img.incoherency.co.uk/2338/thumb"></a></p>
<p>(Sorry there are no axis labels. X-axis is time of day, Y-axis is &deg;C, pink line is desired temperature, blue line is actual temperature)</p>
<p>Ideally I would use a programmable furnace, but my furnace only supports setting a constant target temperature. My solution to "ramping" the temperature
at a consistent rate was to manually increase the target temperature every ~10 minutes. The PID controller on my furnace does an excellent job at maintaining
a constant temperature, but it seems to overshoot the target every time you set a new one. But apart from that, I got the temperature profile almost perfect.</p>
<p>Once the heating was done, I took the chunk of plaster out of the furnace with a pair of pliers and dunked it in a bucket of water. Surprisingly, it floated
at first, and also it burst into flames after I put it in the water. I guess there was lots of trapped gas inside the plaster, and I guess the flames were actually
caused by exposure to oxygen in the air, not exposure to water.</p>
<p>After it cooled down a bit, I fished out some of the chunks of plaster to see what was inside.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2326"><img src="https://img.incoherency.co.uk/2326/thumb"></a></p>
<p>You can clearly see where the outer pieces of charcoal plaster have burned up and turned white, and the inner pieces have not had exposure to oxygen and are still grey. So it looks like the
charcoal plaster, at least, was a success. At this point I thought that was all that was successful, and that the bronze PLA stuff had all just disintegrated,
but swilling the bucket of water around a bit more I was amazed to find this!</p>
<p><a class="img" href="https://img.incoherency.co.uk/2327"><img src="https://img.incoherency.co.uk/2327/thumb"></a></p>
<p>That's a sintered bronze part! Unbelievable. I didn't actually expect it to work, not on the first try. It even feels like it's bonded together pretty well, like an
actual metal part. I squeezed it quite hard to see if it would crumble apart into powder, and it didn't crumble but it did deform:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2339"><img src="https://img.incoherency.co.uk/2339/thumb"></a></p>
<p>So that tells us that the metal is actually sintered together (else it would just crumble), which is a great result, but for some reason it isn't very strong.
I cleaned more of the charcoal plaster remnants off, and sanded the end to see what it looked like:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2329"><img src="https://img.incoherency.co.uk/2329/thumb"></a></p>
<p>That looks great! That's exactly what I'd expect a metal part to look like. I wire-brushed the outside to clean it up a bit, and noticed that the end with the square
drive has some big holes in it:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2331"><img src="https://img.incoherency.co.uk/2331/thumb"></a></p>
<p>So it looks like it's hollow at one end, which is why it deformed when I squeezed it. Indeed, cutting it in half reveals the extent of the hollowness:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2333"><img src="https://img.incoherency.co.uk/2333/thumb"></a></p>
<p>The bronze initially looks like brass after sanding or wire-brushing, but over the course of a few minutes it turns a more coppery colour as (presumably) oxides
form on the surface.</p>
<p><h3>Some thoughts</h3></p>
<p>The filament is 80% bronze by mass, and the density of bronze is about 6x the density of PLA, so that means the filament is actually only 40% bronze by volume.
This is why the part is hollow at the top: there is just not enough material in here to fill the space. I think the material all sinks to the bottom of the void
in the plaster as the PLA starts to boil off, leaving only a thin layer of bronze powder stuck to the sides.</p>
<p>I checked the resistance of the part with a multimeter, and it seems to have negligible resistance. I measured 0.6 Ohms from one end of the part to the other,
and also 0.6 Ohms when connecting my multimeter leads directly to each other.</p>
<p>During sintering, the distance across the flats of the hexagon shrunk from 10.2mm to about 9.3mm (~9% shrinkage, x/y plane). The outside diameter of the socket shrunk from 13.9mm
to 12.8mm (~8% shrinkage, x/y plane), and the height of it shrunk from 20.2 to 19.0mm (~6% shrinkage, perpendicular to x/y plane).</p>
<p>I wanted to connect the socket to a torque wrench to see how much torque it could handle without breaking, but the shrinkage meant I couldn't actually fit it on either
the 10mm bolt head or the 1/4-inch square drive.</p>
<p>Less than 10mm of the charcoal plaster was "used up" by oxygen in the furnace, so I think for the temperature profile that I used here, a 10mm coating of charcoal
plaster would be sufficient. For a much larger part, you would probably need to heat it for longer, and therefore you'd need more charcoal. I suspect the distance
you need around the outside scales linearly with the amount of time it's heated. Also, if you want to switch the furnace off partway through and then resume
another day, you'll probably need extra thickness as some extra charcoal will be used while the furnace cools and then heats up again.</p>
<p><h3>Next attempt</h3></p>
<p>For next time, I'm going to stretch the part by 9% in the X/Y plane, and 6% in the Z axis, to account for shrinkage and hopefully get a sintered part that I can
actually fit on a bolt and a torque wrench.</p>
<p>If the part has shrunk by 9% in the X and Y directions, and 6% in the Z direction, then the total volume is reduced to 0.91*0.91*0.94 = 78% of the original volume. But only
40% of the original volume was bronze, so if we want the entire part to be full of bronze and not hollow at the top, then we need to add an entire extra part's worth
of extra material at the top, so that when it all sinks to the bottom, there is enough material at the bottom to fill the part solid. Since I already have a handful
of 10mm sockets printed in bronze PLA, I might just stick one of those on top to use as sacrificial material.</p>
<p>Also, it would be good if the furnace would follow the temperature profile automatically. There is a good <a href="https://www.youtube.com/watch?v=hGCL1FXKXss">YouTube video
by VegOilGuy</a> about converting a PID furnace to be controlled by a "CAL 9500P" process controller which supports programmable temperature profiles.
A new CAL 9500P is more than &pound;200, but I found a secondhand one on eBay for only &pound;20, so I have bought it and hopefully I'll be able to make it
control my furnace. I would then be able to leave the furnace on overnight, unsupervised, and get up in the morning just in time to quench the part at the end.
That is, depending on how confident I am that the furnace is safe to leave unsupervised at 865&deg;C.</p>
<p><h3>Sintering vs casting</h3></p>
<p>This process is very much like "lost PLA" casting. In lost PLA casting, you print your part in PLA, embed it in plaster, get it hot for a long time to burn off all
the PLA, and then fill the void with molten metal.</p>
<p>In our sintering process, you print your part in PLA that already has metal in, embed it in plaster, get it hot for a long time to burn off all the PLA, and then keep
it hot for a while so that the metal particles stick together. It's not really all that different to casting. The advantage of sintering is that you don't have to pour
any molten metal, which also means you don't have to deal with scraping the slag off, the part warping as it cools non-uniformly, or designing feeders and sprues, etc. The disadvantage of sintering is that
it requires the metal to be in filament form, and it is less forgiving of oxygen contact and incorrect temperatures, and fewer people have attempted to DIY it so there
is less information available.</p>
<p>The big advantage of the sintering process that Markforged, BASF, etc. are doing is that you can make parts with hollow infill. Unfortunately, our process goes
through an intermediate stage where the binder turns to a liquid in the furnace, whereby it flows downhill, and carries the metal powder with it. If we had hollow infill, the infill material
would all sink to the bottom, so we can
only sinter parts that are completely solid, like those that would be produced by casting.</p>
<p>I don't actually understand how Markforged and BASF can print with a material that obviously becomes runny at about 250&deg;C, and yet retains its shape while in the
sintering furnace at 1300&deg;C. It would be good to learn more about how this works.</p>
<p><h3>Help still wanted</h3></p>
<p>I'm still interested in hearing ideas for improvements to this process. Particular problems that want solving include:</p>
<p><ul>
<li>how can we prevent the part from becoming runny in the furnace? (e.g. for hollow infill)</li>
<li>is there a temperature profile that would do the debinding and sintering in substantially less time?</li>
<li>is the "catalytic debind" of the BASF filament DIY-able?</li>
<li>what's the cheapest way to acquire a vacuum furnace suitable for sintering stainless steel?</li>
</ul></p>
<p>If you've done any sintering, I'm interested in hearing about it. And if you reproduce the steps described in this post, I'm also interested in
hearing about how that goes.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/metal-3d-printing-first-results.html</link>
   <guid>http://incoherency.co.uk/blog/stories/metal-3d-printing-first-results.html</guid>
   <pubDate>Mon, 12 Aug 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The 2019 BLMRA 12 hour lawnmower race</title>
   <description><![CDATA[
We raced at the BLMRA 12 hour again this year.]]></description>
   <content:encoded><![CDATA[<p>
We raced at the BLMRA 12 hour again this year.</p>
<p><h3>Preparation</h3></p>
<p><a href="https://incoherency.co.uk/blog/stories/blmra-12-hour-2018.html">Last year's 12 hour</a> went well, with delays caused only by the bent clutch and flat tyres. Additionally the mower didn't
handle as well in slow wet conditions as it did in hard dry conditions. So with that in mind, for this year I built a new clutch out of a more substantial piece of steel:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1924"><img src="https://img.incoherency.co.uk/1924/thumb"></a></p>
<p>And replaced the old lawnmower wheels with the fancy wheels that everyone else uses that have little bolts around the rim to keep the tyre from falling off:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1926"><img src="https://img.incoherency.co.uk/1926/thumb"></a></p>
<p>And improved the steering geometry by separating the inner track rod ends:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2252"><img src="https://img.incoherency.co.uk/2252/thumb"></a></p>
<p>I have <a href="https://www.youtube.com/watch?v=4Di335znd1g">a video of a 3d-printed prototype</a> from before I committed the design to steel.</p>
<p>Previously both inner rod-ends were mounted in the same place. This meant that as the steering shaft rotates, both track rods move left/right by
the same distance. By separating the ends, the rod end which is at the "bottom" moves primarily in the horizontal axis, while the rod end that is
at the "side" moves more in the vertical axis, which reduces its horizontal movement, which means the inside wheel is pulled by more distance than
the outside wheel is pushed, getting us closer to <a href="https://en.wikipedia.org/wiki/Ackermann_steering_geometry">true Ackermann</a> geometry.</p>
<p>We also added <a href="https://incoherency.co.uk/blog/stories/arduino-rev-limiter.html">an electronic rev limiter</a> and made a handful of other small improvements.</p>
<p>The new wheels use smaller hubs, which have smaller bearings than we were using before. After our test weekend the front wheel bearings were feeling
slightly gritty so I picked up a new pair of hubs from <a href="http://www.randmracing.co.uk/">R&M Racing</a> on the Saturday morning of the race,
and fitted them, so that we'd have fresh bearings to race with.</p>
<p><h3>The race</h3></p>
<p><a href="http://curbedambition.com/">James</a> and I drove the mower again, but <a href="https://www.ferozsalam.com/">Feroz</a> couldn't drive because of eye trouble,
so we had <a href="https://www.instagram.com/ruaribush/">Ruari</a> driving this year. <a href="https://caconym.co.uk/">Matt Game</a> came to help in the pits again, and
<a href="http://www.thelifeadventuristic.co.uk/">Rory Lucas</a> also came to help in the pits, along with Emma and Catherine (James's wife) taking care of hospitality and timing.</p>
<p>We passed scrutineering on the first try, which was good. I wasn't sure whether our front axle was now too wide, or if they would take issue with the presence of the
rev limiter. But they measured the distance between the front wheels and were happy with it, and they didn't notice the rev limiter.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2307"><img src="https://img.incoherency.co.uk/2307/thumb"></a></p>
<p>James and Ruari did their practice sessions with no incident, but when I set off for mine the belt started making an awful noise, and when I lifted off the throttle
at the first corner, it jumped off the front pulley and got a bit shredded. That's annoying. I thought we'd solved all the belt problems by now.
The circuit this year was on a field that was not quite level, so there were 2 men in a "Gator" towing mowers back up the hill. I got a tow back to our pit garage and
we put a new belt on.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2309"><img src="https://img.incoherency.co.uk/2309/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/2320"><img src="https://img.incoherency.co.uk/2320/thumb"></a></p>
<p>We qualified 33rd, but I only got about 5 laps of qualifying. I'm not sure which one of us set the best time in qualifying, but I think I at least would have been
able to do faster laps if I had got some practice in beforehand.</p>
<p>James got a good start, and his first stint went OK for the most part.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2319"><img src="https://img.incoherency.co.uk/2319/thumb"></a></p>
<p>At one point someone hit him from behind and one of the mudflaps got stuck under the wheel arch.
James didn't know what had happened and was concerned about the noise it was making, so he made a pit stop. We briefly tried to pull the mudflap out but it was too
stuck so we just left it and he carried on. Subsequently he broke down and got towed back. But we couldn't find anything wrong with the mower, and it started up OK
by the time it got back to the pit, so we refuelled and Ruari set off for his first stint, which, apart from a brief pause to throw off his steamed-up goggles,
was completed without issue. At this point we speculated that James might have ran out
of fuel, as the breakdown was near the end of the hour, although we know that a tank of fuel normally lasts just over an hour.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2321"><img src="https://img.incoherency.co.uk/2321/thumb"></a></p>
<p>After Ruari finished his hour, I went out for my first stint.
This mostly went without issue, and I was enjoying it very much. The mower handled really well, and
it was much more pleasant to drive on long straights with the rev limiter, rather than having to lift off the throttle.
About 51 minutes in the engine started sputtering and backfiring, which is a sign that it is running on fumes and about to run out of fuel, so I pitted and
we refuelled it, then I carried on to finish the hour. At this point we were pretty confident that James had stopped due to running out of fuel, so we altered
the pit strategy to include a quick refuel stop halfway through each stint. The track this year was much faster than previous years, so we were obviously using
fuel faster. Also, whenever we're hitting the rev limiter instead of lifting off the throttle, we're chucking a load of unburnt fuel out the exhaust that we
previously wouldn't have been.</p>
<p>James and Ruari's second stints were both pleasantly uneventful, but on my second stint the belt jumped off the front pulley again. This is extremely annoying. 
The belt wasn't visibly damaged this time so we just refitted it and carried on. It jumped off again in James's third stint, and again we refitted it and carried on.</p>
<p>Ruari had gone to sleep after his second stint, and had set his alarm incorrectly, so at 2.50am, 10 minutes before he was due on for his third stint, he was quickly
awakened from a deep sleep. It was quite cold at this point of the morning, and waking up quickly from a deep sleep didn't help. I've never seen anyone shivering
as much as Ruari was then. We tried to give him a can of energy drink, but he couldn't hold it still enough to avoid shaking the contents out the top. James's
stint ended with the belt jumping off again, which gave Ruari a few more minutes to wake up while we refitted it again.</p>
<p>At the start of my third stint, I merged onto the track in amongst traffic. I wasn't yet in "race mode", having been sitting in the pits only 15 seconds
prior, and quite badly missed my braking marker for the first corner. When I realised my mistake I braked hard, and miraculously managed to avoid hitting any of the 
other mowers, but my mower swung around a bit and slammed into a large hay bale. The mower was thrown up in the air a bit and ended up facing the wrong way, but I
was still on it and it wasn't obviously damaged, so I turned round and carried on. Over the course of this stint the bonnet became increasingly wobbly, and
eventually it was getting too bad so I had to pit so that we could repair it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2322"><img src="https://img.incoherency.co.uk/2322/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2323"><img src="https://img.incoherency.co.uk/2323/thumb"></a></p>
<p>It got cracked in the crash, and the crack was spreading as it was wobbling around. We repaired it by drilling holes either side of the cracks and tying them
together with cable ties.</p>
<p>After this I carried on some more and the belt jumped off again. We decided to fit a new belt at this point to see if that would cure anything, which ended up
costing 18 minutes, but did solve the issue for the rest of the race. Right at the end of the stint the front left wheel became wobbly, so I pitted and we found
that one of the wheel bearings had collapsed. Good job we had a spare pair of hubs! Part of the collapsed bearing was stuck to the spindle, so this was removed
with the angle grinder, but changing the hub only took a couple of minutes.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2311"><img src="https://img.incoherency.co.uk/2311/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2310"><img src="https://img.incoherency.co.uk/2310/thumb"></a></p>
<p>James's final stint was completed without issue. In Ruari's final stint somebody else had a big accident which resulted in "full-course yellows" for a few laps.
This means there are flashing yellow lights and no overtaking is allowed. All of the mowers bunch up together. When the full-course yellows were over, Ruari
was in amongst a bunch of faster mowers, and ended up setting his fastest lap. About 10 minutes before the end of his stint, he pitted because one of the rear tyres
was low on air. We put a new one on and then I went out for my final stint.</p>
<p>I realised quite quickly that the rev limiter was no longer working, but I wasn't sure why. After a few laps the mower sputtered to a halt. I managed to pull
off the track and noticed that fuel was gushing out of the bottom of the fuel tank. That was quite concerning. I got off and held my finger over the bottom of the
tank to stop the flow of fuel and awaited assistance from the pit crew. I also noticed at this point that the fuel tank was very loose, and the live wire that powers the rev limiter was
broken in half. We later concluded that the fuel tank had got knocked off its mounts during the crash at the start of my third stint, and had been slowing working
its way free. It was then able to wear through the wire for the rev limiter, and eventually knocked the fuel hose off. Having a loose live wire flapping around
next to a fuel leak is the closest we've ever come to a fire, but thankfully it didn't result in one.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2312"><img src="https://img.incoherency.co.uk/2312/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2313"><img src="https://img.incoherency.co.uk/2313/thumb"></a></p>
<p>Emma ran to the pit to fetch the tools to take the bonnet off, and then we reconnected the fuel hose and pushed the mower back. We removed the loose live
wire, secured the fuel tank with more cable ties, and continued racing.</p>
<p>With about 20 minutes left to go, the front right wheel bearing wore out, the same way the
left had earlier on. I cut across the track and drove straight to our pit where we quickly changed the hub and carried on. In hindsight I should probably have attempted
to complete the lap I was on, because I ended up cutting out more than half of the lap. I was just concerned that the wheel would fall off entirely if I kept driving.</p>
<p>After that the belt started slipping a bit. I was concerned that it was damaged and was going to break, which would have been fatal as at this point we would not
be able to put a new belt on in time to finish the race. So I drove quite gingerly, making sure not to put too much strain on the belt, and eventually crossed
the checkered flag!</p>
<p><a class="img" href="https://img.incoherency.co.uk/2315"><img src="https://img.incoherency.co.uk/2315/thumb"></a></p>
<p>We finished 26th overall, of 50 entries. We were also given the "best pit" award, although we don't know why, and we didn't actually receive it as we were sleeping during the prizegiving. Current theory is that it was a joke because our pit was full of drinks and snacks instead of tools and spares.</p>
<p>We wasted about 90 minutes in total on unexpected repairs to the mower, in which time we would have been able to do 40-45 extra laps, which would have gained us
7 places.</p>
<p><h3>For next time</h3></p>
<p>People want me to build a new mower from scratch, but I don't think I'm going to. I'm currently planning to strip the current mower down to the chassis, and
then build it up as if I was building a new one from scratch. I don't think the Countax chassis is actually that bad. There's certainly scope to do a better job of it
than I have done so far.</p>
<p>We need to get to the bottom of the belt falling off. When it comes off, it always comes off the top of the front pulley, never the rear, even though the front
pulley has some rollers next to it to keep the belt from coming off and the rear pulley has nothing. It also seems to happen more as the belt gets worn out,
possibly because the belt gets more flexible. After the race I measured the rear pulley and found that it is
out of level by about 1&deg;, pointing up at the front. When you lift off the throttle (and the "tight" run of the belt from the front to the rear
turns into a "slack" run) the rear pulley is pushing the belt forwards with quite a lot of power. If it's pushing hard enough, then that might be enough to force the
belt up and past the rollers by the time it gets to the front pulley. Some of the other mowers don't have anything at all to keep the belt on the front pulley, and
they don't seem to have it fall off as often as we do, so I'll definitely make sure to fit the rear pulley square to the chassis.</p>
<p>Additionally, Matt had a great idea for a better way to keep the belt on. Instead of having rollers on the chassis, next to the pulley, we should instead just
make the pulley larger by fitting big metal plates at the top and bottom:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2324"><img src="https://img.incoherency.co.uk/2324/thumb"></a></p>
<p>The metal plates are fixed to the pulley, and spin around with it, so that even if the belt gets slack and lifts away from the pulley, it still can't move up or down, so
it'll just re-engage with the pulley as soon as it becomes tight again. The bottom plate might need to be removable so that we are able to fit the belt, but the top
one at least can be permanently welded to the pulley.</p>
<p>I was very disappointed with the bearings in the new front hubs. R&M Racing inform me that they're working on a new hub design that takes larger bearings. If that
comes to fruition then I'll probably just buy them, or alternatively I might try to machine some new hubs of my own. It's not a very complicated part, it could just
be a big chunk of aluminium with a hole up the middle for the bearings to sit in, and 3 concentric threaded holes on one face for the rims to bolt
on to. The only tricky bit is making sure the 3 holes are actually concentric. Ideally you'd use a milling machine, but I think a template and a pillar drill would
suffice.</p>
<p>The new wheels did a great job of keeping the bead from breaking when the tyres got low on pressure, although the tyres got low on pressure faster than they should.
I'm not entirely sure where they're leaking, but I'd like to stop them leaking for next year. Possibly they just want refitting using bead sealant around the bead and
on the bead-retention bolts.</p>
<p>We should fit some sort of battery isolator so that next time there is an exposed live wire, we can just immediately disconnect the battery and rule out any unwanted sparks.</p>
<p>The centre of gravity wants lowering, as does the seat.</p>
<p>And also it wants a better bracket for the fuel tank, so that it can't fall off even if you have a big crash.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/blmra-12-hour-2019.html</link>
   <guid>http://incoherency.co.uk/blog/stories/blmra-12-hour-2019.html</guid>
   <pubDate>Fri, 09 Aug 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>An interesting 3d metal printing process (help wanted)</title>
   <description><![CDATA[I recently learnt about the Markforged Metal-X 3d printer from a post on 3DP Reviews. It costs
$100k USD, and can print metal objects. As far as I can tell, it is essentially an ordinary FDM printer, with a special filament that contains
a high percentage of metal powder held together with a "binder". After printing, the part is washed in a solvent to remove most of the binder, and finally it is
heated in a furnace to sinter the metal powder together.]]></description>
   <content:encoded><![CDATA[<p>I recently learnt about the <a href="https://markforged.com/metal-x/">Markforged Metal-X</a> 3d printer from a post on <a href="https://www.3dpreviews.co.uk/post/metal-3d-prints-markforged-metal-x">3DP Reviews</a>. It costs
$100k USD, and can print metal objects. As far as I can tell, it is essentially an ordinary FDM printer, with a special filament that contains
a high percentage of metal powder held together with a "binder". After printing, the part is washed in a solvent to remove most of the binder, and finally it is
heated in a furnace to sinter the metal powder together.</p>
<p>There's <a href="https://www.youtube.com/watch?v=uOwWxC-OmZg">a good video</a> giving an explanation.</p>
<p>I got very excited by how simple it looks in the video, and I'd like to be able to DIY this process without spending the $100k.
This blog post is everything I currently know about what would be required.</p>
<p><h3>1. Printing</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/2287"><img src="https://img.incoherency.co.uk/2287/thumb"></a></p>
<p>The Metal-X system has a dual-extruder printer, with a ceramic material printed as an interface layer between the metal support material and the
metal part. I understand that the ceramic material turns to a powder in the furnace, which allows easy separation of the part from its supports.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2286"><img src="https://img.incoherency.co.uk/2286/thumb"></a></p>
<p>But we don't need to worry about detaching the support material. We can worry about that later, if we can get the rest of it to work. A single
extruder will do to start with.</p>
<p>The Markforged printer has a heated build chamber. I'm not sure if this is <i>necessary</i>,
or if it's just expected as standard when you're dropping $100k on a printer.
I don't know what temperature the filament is printed at, but I expect it's not too much higher than normal 3d printing temperatures, as the printing stage doesn't
actually have to melt the metal, it just needs to extrude the binder material.</p>
<p>The part that comes out of the printer is considered "green", and is about 80% metal (by volume) and 20% binder.</p>
<p>I would love to get hold of some Metal-X filament
and try to print it with an ordinary hobbyist machine to see what happens. If it turns out to need a heated chamber, that's doable, and if it turns out to
need a hotter hot-end, that's doable too. There is actually some "A2 tool steel" filament
<a href="https://markforged.com/product/f-mf-1007/">in stock on their website</a> (at time of writing), but it is going to cost $400 to have it
shipped to me, which is a lot of money to spend only to find out that it's not going to work. And I don't actually know if they are willing
to ship filament to people who haven't bought the $100k printer. But if they are, this might be a good place to get it.</p>
<p><h3>2. Washing</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/2288"><img src="https://img.incoherency.co.uk/2288/thumb"></a></p>
<p>As far as I can tell, you just soak the part in an appropriate solvent (more on this later) for a while, until most of the binder has gone. You can check how
much binder remains
by weighing the part: when it has reduced in mass (by whatever percentage the binder is by mass), you know all the binder is gone. Although, I suspect you don't actually want to remove 100% of the
binder as then you'd just be left with a pile of powder. In the picture, the operator has labelled each part with its original mass before washing.</p>
<p>The Markforged CAD software in the cloud (ugh) gives an estimate of the required printing and washing time:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2289"><img src="https://img.incoherency.co.uk/2289/thumb"></a></p>
<p>This 8-hour print is going to take 33 hours to wash! I imagine the washing step is quite necessary, otherwise it would not be worth spending 33 hours on, although
I don't know what would actually go wrong if you just chucked the green part straight in the sintering furnace.</p>
<p>I don't know if the washing machine agitates or heats the solvent, but from our perspective this is just a case of figuring out the best process. There
doesn't seem to be any complicated engineering here.</p>
<p>The washed part is considered "brown".</p>
<p><h3>3. Sintering</h3></p>
<p>Finally, the brown part is heated in a furnace to sinter the metal powder particles together.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2291"><img src="https://img.incoherency.co.uk/2291/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/2292"><img src="https://img.incoherency.co.uk/2292/thumb"></a></p>
<p>The finished part has shrunk in size by 20% because the binder material is no longer present.</p>
<p>One of the few pieces of useful information available on the Markforged website is that their furnace
can reach a peak temperature of 1300&deg;C:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2290"><img src="https://img.incoherency.co.uk/2290/thumb"></a></p>
<p>Most of the cheap furnaces I could find on eBay reported a max. temperature of about 1100&deg;C, so we might need something more fancy here.</p>
<p>I suspect it is quite important that the chamber is heated uniformly to prevent the part from warping as it shrinks, but if we could produce even a <i>warped</i> 3d
printed metal part, that would be a very good starting point. You'll also notice some o-rings around the door of the chamber, and the operator screws the door
on before the heating starts. This implies that the furnace needs to be air-tight, possibly it is under vacuum to prevent the metal from oxidising.</p>
<p>If the furnace indeed needs to reach 1300&deg;C, and needs to be under vacuum, then the furnace will probably end up being the most expensive part of this
whole affair.</p>
<p><h3>Metal Injection Moulding</h3></p>
<p>Most of this process is exactly the same as in <a href="https://en.wikipedia.org/wiki/Metal_injection_molding">Metal Injection Moulding</a>, except an FDM printer
takes the place of the mould and injector.</p>
<p>Several different binders are used in MIM, some of which are water-soluble, and some of which require catalytic debinding in an "acidic gaseous atmosphere". Obviously
it is more convenient for us if we can wash the green part in water rather than trying to safely contain an "acidic gaseous atmosphere".</p>
<p><h3>Sourcing filament</h3> </p>
<p>Aside from buying filament from Markforged, there are a few more options.</p>
<p>I found a kickstarter from a few years ago called
<a href="https://www.kickstarter.com/projects/1093108121/sinterhard-metal-filled-filaments-for-3d-printing">Sinterhard</a>, whose goal was to produce filament
for exactly this kind of process, although it never ended up succeeding. In the <a href="https://www.kickstarter.com/projects/1093108121/sinterhard-metal-filled-filaments-for-3d-printing/posts/1667406">final update</a>, they write:</p>
<p><blockquote>4)  We relatively quickly discovered that the target metal fill rates using PLA and ABS were making filament that would not spool [too stiff and too brittle].</p>
<p>5)  We exhausted trying plasticizers and lubricants to get a flexible high fill rate on the PLA and ABS.  [Not to say it won't work, but we did not find the magic formula that did work].  Making "stick" filaments, with a new feed system is a viable alternative, however, that was not our mission goal.</blockquote></p>
<p>And interestingly enough, there is a company <a href="https://www.desktopmetal.com/">Desktop Metal</a> who sell a metal 3d printer that uses <i>sticks</i> instead of
spools of filament. If stick-style material is easy to acquire, it would probably be easy enough to make an extruder
that can use it. So this is another potential avenue to explore.</p>
<p>I also found out that BASF manufacture a product called <a href="https://www.basf.com/global/en/who-we-are/organization/locations/europe/german-companies/basf-3d-printing-solutions-gmbh/metal-solutions/Ultrafuse_316L.html">Ultrafuse 316L</a>, which is 90% stainless steel by mass. BASF give a lot more information than Markforged do. The Ultrafuse 316L is available in both 1.75mm and 2.85mm diameter, extrudes at 230&deg;C-250&deg;C, and wants a 90&deg;C-120&deg;C bed temperature, which is high but fine.
So this stuff looks ideal, but as far as I can tell it isn't actually available to buy anywhere. <a href="https://essentium3d.com/products/metalfilament">Essentium</a>
have it listed for sale, but it's a "contact us to order" jobby, which implies we can't afford it. <a href="https://www.matterhackers.com/store/l/essentium-basf-ultrafuse-316l-metal-composite-3d-printing-filament-175mm/sk/M3R07U9R">Matterhackers</a> have it as "coming soon".</p>
<p>Failing all of the above, it's not completely implausible that we could buy MIM feedstock in pellet form and extrude it into filament at home. This is a rabbit hole
I'd rather not go down, but it could be a possibility. And again, I don't know who would be willing to sell it cheaply in tiny quantities to hobbyists.</p>
<p><h3>Help wanted</h3></p>
<p>So, that's everything I know about MIM-style 3d metal printing. If you're interested in this project I want to hear from you.</p>
<p>I am particularly interested in hearing about: potential problems that I have overlooked, prior hobbyist efforts in this space, suggestions for how to cheaply build or
acquire a suitable furnace, suppliers of MIM feedstock or filament who would be willing to sell to hobbyists, experience people have with the Metal-X or
Desktop Metal machines, experience with the MIM process, experience with extruding your own filament.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/metal-3d-printing.html</link>
   <guid>http://incoherency.co.uk/blog/stories/metal-3d-printing.html</guid>
   <pubDate>Sun, 28 Jul 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to make a rev limiter with an Arduino</title>
   <description><![CDATA[My racing mower has a tendency to
over-rev on long straights. To avoid damaging the engine, we have been lifting off the throttle, but a more reliable
solution would be an electronic rev limiter.  
I did buy a commercial rev limiter made by AccuSpark, but was unable to fit
it to my mower because the AccuSpark unit needs access to both sides of the ignition coil, and my ignition coil
is inaccessible, inside a black box with all the other ignition electronics. So my solution was to make a rev limiter with an Arduino.]]></description>
   <content:encoded><![CDATA[<p>My <a href="https://incoherency.co.uk/blog/tags/lawnmower.html">racing mower</a> has a tendency to
over-rev on long straights. To avoid damaging the engine, we have been lifting off the throttle, but a more reliable
solution would be an electronic rev limiter.  
I did buy a <a href="http://accuspark.co.uk/pending.html">commercial rev limiter made by AccuSpark</a>, but was unable to fit
it to my mower because the AccuSpark unit needs access to both sides of the ignition coil, and my ignition coil
is inaccessible, inside a black box with all the other ignition electronics. So my solution was to make a rev limiter with an Arduino.</p>
<p>To limit how fast the engine can run, our project just needs to measure how fast the engine is running, and kill the ignition
when it's running too fast.</p>
<p><h3>Sensing RPM</h3></p>
<p>The flywheel has a large magnet on it for the ignition electronics, so to detect the engine RPM I
bent up a small piece of steel to hold a magnet sensor near the flywheel:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2264"><img src="https://img.incoherency.co.uk/2264/thumb"></a></p>
<p>This triggers an interrupt in the Arduino code once every time the engine rotates, and the time between interrupts can be used to calculate the engine RPM (e.g. at 20ms
between interrupts, the engine is turning at 3000rpm).</p>
<p><h3>Killing the ignition</h3></p>
<p>The black box ignition electrics provides a convenient way to kill the engine, you just short the kill switch
wire to ground and then the signal for the spark is shorted to ground instead of generating a spark. The downside is
that this is quite hard to do electronically. From what I've read online, the signal on this wire is roughly a 15 microsecond pulse
of 150v AC.</p>
<p>I first tried to switch the kill switch wire with an NPN transistor, but couldn't get this to work. I also tried
an N-channel MOSFET and couldn't get that to work either. In both cases, everything I tried either never killed the ignition, or
always killed it.</p>
<p>Eventually I bought a solid-state relay and that worked much better. I suspect the problem was that the 
transistor and MOSFET can't handle the voltage, AC, or both, whereas the solid-state relay is designed for 240v AC.
You might get away with using a mechanical relay instead of a solid-state one, but driving it is inconvenient as
it takes more current than the Arduino outputs can supply, and the rapid switching
would result in premature wear.</p>
<p>The solid-state relay I used was an Omron G3MB-202P, and it looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2282"><img src="https://img.incoherency.co.uk/2282/thumb"></a></p>
<p><h3>Installation</h3></p>
<p>Having made the rev limiter work on a breadboard, I made up a piece of copper stripboard with an Arduino Nano, the solid-state relay,
and the requisite connectors:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2268"><img src="https://img.incoherency.co.uk/2268/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2271"><img src="https://img.incoherency.co.uk/2271/thumb"></a></p>
<p>(although, the project is simple enough that you could get away with ignoring the stripboard altogether and just soldering wires between
the components).</p>
<p>I carved out some isolation around the high-voltage parts because I was paranoid about the 150v pulse arcing to adjacent traces and damaging
the Arduino, but the gap is probably large enough that it wouldn't.</p>
<p>The connectors we need are a USB cable for reprogramming the Arduino, a connector for power supply from the mower battery, a cable
to connect to the hall effect sensor (with 2.5mm audio jack for convenience), and a wire to connect to the kill switch wire (with spade connector).</p>
<p>I 3d printed a case:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2272"><img src="https://img.incoherency.co.uk/2272/thumb"></a></p>
<p>As you can see, the actual project only takes up about half the space inside the case. The rest is taken up by the inconvenient USB plug.
A much better way to design the case would be to have the wires
coming out of one end instead of out of the top. It would also be helpful to lie the solid-state relay on its side, parallel to the
Arduino.</p>
<p>I potted the board in to the case with polyurethane resin to protect it from water and vibration:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2273"><img src="https://img.incoherency.co.uk/2273/thumb"></a></p>
<p>and bolted it inside some bodywork on the mower:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2274"><img src="https://img.incoherency.co.uk/2274/thumb"></a></p>
<p>The last Arduino project I did for a vehicle was the <a href="https://incoherency.co.uk/blog/stories/scooter-speedo.html">speedo driver for my scooter</a>. Lessons
learned from that project include:</p>
<p><ul>
<li>an Arduino Nano is easier to use than a raw ATmega328p, as it includes its own voltage regulator and a USB connector</li>
<li>female connectors on the circuit board are to be avoided as they are liable to fill up with resin</li>
<li>it's easier to secure the electronics to the vehicle if the case has mounting holes</li>
</ul></p>
<p><h3>Software</h3></p>
<p>You can get the Arduino code <a href="https://github.com/jes/revsafe/blob/master/revsafe.ino">on github</a>. It's not very complicated.
It keeps track of the last 2 times (in microseconds) at which the interrupt fired, and then the main loop is a busy loop that constantly checks the current RPM
based on these times, and makes the relay connect the kill switch wire to ground if the RPM is too high, and disconnect it if the RPM is low enough.</p>
<p>I also made it <a href="https://thekurks.net/blog/2018/1/24/guide-to-arduino-sleep-mode">put the microcontroller into sleep mode</a> after the engine has not been running
for 10 seconds, in order to avoid wasting power spinning the busy loop while the engine is not running.</p>
<p>We have ran the mower for 2 or 3 hours with this rev limiter, and it still seems to work.</p>
<p>I have <a href="https://www.youtube.com/watch?v=mJI9jHpJHlo">a video demonstrating the rev limiter</a>, although in the video the engine is not bolted down
properly, and the Arduino code only measures the RPM with milliseconds instead of microseconds. But it works, and it shows the idea.</p>
<p>The program writes the current RPM to the Serial console 10 times per second, suitable for use with the Arduino "serial plotter" to get a live plot of the engine speed.</p>
<p>The redline is configured by editing the <tt>max_rpm</tt> constant in the Arduino code. I expect this will be fine, but if you expect to have to adjust it a lot,
you could read it off a potentiometer instead.</p>
<p>The worst part about editing the code in-the-field is that the laptop screen can be hard to see even on an overcast day:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2284"><img src="https://img.incoherency.co.uk/2284/thumb"></a></p>
<p><h3>Better mounting holes</h3></p>
<p>In addition to reorienting things so as to use the space inside the case more efficiently, I thought it would be a good idea to make the space around
the holes hollow:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2283"><img src="https://img.incoherency.co.uk/2283/thumb"></a></p>
<p>This would actually be stronger, as the resin would reinforce the holes, instead of just relying on the strength of the 3d print.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/arduino-rev-limiter.html</link>
   <guid>http://incoherency.co.uk/blog/stories/arduino-rev-limiter.html</guid>
   <pubDate>Mon, 22 Jul 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>My first chess tournament</title>
   <description><![CDATA[
At the weekend, Bristol Grammar School played host to the June 2019 Bristol Chess Congress, the "13th Steve Boniface Memorial".
It's a 5-round Swiss tournament, with 3 sections: open (for international rated players), major (players with ECF grade
under 160), and minor (ECF grade under 120). Having never played in a rated tournament before, I don't have an ECF grade at all, so I was obviously in the minor section.]]></description>
   <content:encoded><![CDATA[<p>
At the weekend, Bristol Grammar School played host to the June 2019 <a href="https://www.bristolcongress.co.uk/">Bristol Chess Congress</a>, the "13th Steve Boniface Memorial".
It's a 5-round <a href="https://en.wikipedia.org/wiki/Swiss-system_tournament">Swiss tournament</a>, with 3 sections: open (for international rated players), major (players with <a href="https://en.wikipedia.org/wiki/English_Chess_Federation">ECF</a> grade
under 160), and minor (ECF grade under 120). Having never played in a rated tournament before, I don't have an ECF grade at all, so I was obviously in the minor section.</p>
<p><h3>Game 1: Black against Tim McCullagh</h3></p>
<p>The first game was on Friday evening. I arrived half an hour early, not knowing what would be expected of me before the game. It turns out: absolutely nothing.
You just look at the sheet to see which board
and colour you're playing, and then go and sit in the correct chair before the game starts. So I had the best part of half an hour to sit around wondering what I was doing there.</p>
<p>Tim hadn't arrived at the time the game was supposed to start, and I wasn't completely sure whether I was supposed to start his clock or not. Eventually I started it, and then
eventually he turned up, about 3 minutes late. I subsequently saw him do this in at least 2 more games, so it's probably psychological tricks. Fair enough.</p>
<p>I thought the game mostly went well. Tim had a bit of an attack going, and I thought I had successfully fended it off. We reached this position:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2256"><img src="https://img.incoherency.co.uk/2256/thumb"></a></p>
<p>White to move and mate in 2 (answers at bottom).</p>
<p>Tim found the correct move, and after staring dumbfounded for a minute or so, I resigned. But that's a nice finish, I don't mind losing to that. After the game
he said he thought I defended well, but I think he was just being nice.</p>
<p><a href="https://lichess.org/eiNRncii/black" class="btn btn-primary">View game on lichess &raquo;</a></p>
<p><h3>Game 2: White against Mayank Palav</h3></p>
<p>This game was on Saturday morning.</p>
<p>Mayank Palav can't have been much older than 10, so I was not expecting a very difficult game.</p>
<p>It was mostly a pretty even game. After 31 moves we reached a king-and-pawns ending which I thought was winning for me, but which Stockfish
assesses as dead equal. Unfortunately, I cocked it up and Mayank didn't, and I resigned when it was clear that he was definitely queening a
pawn and I definitely wasn't:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2257"><img src="https://img.incoherency.co.uk/2257/thumb"></a></p>
<p>Not bad for a 10-year-old boy.</p>
<p><a href="https://lichess.org/PAFyTRpY" class="btn btn-primary">View game on lichess &raquo;</a></p>
<p><h3>Game 3: Black against Kawagasabai Balasubramaniam</h3></p>
<p>Saturday afternoon.</p>
<p>During the game, I thought Kawagasabai played the opening really badly. I thought he had just lost a pawn for no reason, so I was feeling pretty
chuffed with myself. After winning the pawn, I withdrew my bishop to avoid any trouble with his knight coming to g5 and then f7, and according to Stockfish this is where my problems began.
After move 7 I realised I was in trouble, and it actually took me a long time to find a plan that didn't result in getting mated imminently. So I lost
a knight on move 8, but the game continued.</p>
<p>I subsequently learnt that the opening he played has a name. It's the <a href="http://www.ianchessgambits.com/scotch-gambit.html">Scotch Gambit</a>,
and I walked headfirst straight into it.</p>
<p>So after losing a piece, but not getting mated, the game continued. We traded off most of the pieces, and then reached an ending where he still had the additional piece,
and was able to slowly hoover up all of my pawns, and I eventually resigned:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2258"><img src="https://img.incoherency.co.uk/2258/thumb"></a></p>
<p>So this game was essentially won in the opening. Tricksy bloody e4 openings.</p>
<p>I was feeling pretty low about my chess on the Saturday evening. The way the pairing system works is that you generally play games against people who have
performed about as well as you have. So if you lose your first 2 games, chances are you'll play the 3rd game against someone else who has also lost their
first 2 games. So I'm playing against the worst people, in the lowest-rated section of the tournament, and losing every single game. This is not what
I'm used to when playing online.</p>
<p><a href="https://lichess.org/1THQThvL/black" class="btn btn-primary">View game on lichess &raquo;</a></p>
<p><h3>Game 4: Black against John Stubbs</h3></p>
<p>Sunday morning.</p>
<p>The pairings sheet said I was given a <a href="http://www.chessparents.net/blog/what-is-bye">bye</a>, as there were an odd number of players playing
that morning. You can request a bye in the tournament, for which you receive half a point but don't get the chance to play a game. Since I did not
request this bye, I received a full point instead, although I did not understand this at the time.</p>
<p>The arbiter informed me that if a player doesn't show up, I'll have a game against the person with no opponent, and in the event that everyone shows up,
I'll have a game with John instead, who isn't actually playing in the tournament. About 5 minutes into the round, everyone had arrived, so John and I sat down to play.</p>
<p>The game was mostly very equal, and took a very long time. John was using a lot of time, and started getting in time trouble towards
the end. After one move he forgot to hit the clock, and I pointed it out to him as I wanted to win the game on the board rather than by him blundering
the clock. He also offered me a draw at one point but I declined.</p>
<p>After about 3 and a half hours of playing, we reached this position. I'm a piece up, all my
pieces are good, and Stockfish evaluates the position as 10 points better for black. It's clearly winning for black:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2259"><img src="https://img.incoherency.co.uk/2259/thumb"></a></p>
<p>Now: black to play and find the only losing move (answers at bottom).</p>
<p>John was in a lot of time trouble here, and I thought he obviously didn't have any winning chances,
so I just quickly moved my king out of check, towards John's king, to potentially help with mating him. Unfortunately, I found the only losing move.
John spotted the checkmate, so I lost this game as well.</p>
<p>I was frustrated to lose this game. Not least because I'd helped John with his clock, and also refused a draw. John said he genuinely felt sorry for beating me.
I was pleased, though, that I had at least managed to reach a winning position. In the previous 3 games I was just equal or lost, with no real chances.</p>
<p>I received a full point for playing it anyway. Still would have been nice to win one. Currently at 0 out of 4.</p>
<p><a href="https://lichess.org/1wQDICom/black" class="btn btn-primary">View game on lichess &raquo;</a></p>
<p><h3>Game 5: White against Louis Archer</h3></p>
<p>Sunday afternoon.</p>
<p>I was quite tired going into this game, having played 4 long games over 3 days, and particularly after the previous game lasting 3 and a half hours.</p>
<p>It was mostly a pretty equal game. I had an opportunity to win a piece during the middlegame, but failed to spot the tactic. We reached a position where Louis
had a bishop and a rook, I had a knight and a rook, and I had an extra pawn. I was quite happy with this position, although it wasn't quite clear how to
win it. Louis made the mistake of trading off the rooks, which made things a lot simpler. My additional pawn was useful as it was well-positioned
to stop his pawns from queening:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2260"><img src="https://img.incoherency.co.uk/2260/thumb"></a></p>
<p>The biggest question I had at this point was whether it was more important to quickly queen one of my pawns, or to use my king to try and stop his pawns.
I eventually decided to move the king across and was able to successfully block his pawns:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2261"><img src="https://img.incoherency.co.uk/2261/thumb"></a></p>
<p>I actually expected Louis to resign at this point, but he played on. It was quite a straightforward game from here, and I eventually checkmated him!</p>
<p>That was great fun. I was delighted to finally get a win, and it was a fantastic end to the tournament. Louis and I went over the game on a spare
board in the "analysis room" afterwards, which was a useful chance for each of us to learn what the other was thinking.</p>
<p>And thanks to my full-point bye in game 4, I actually beat Louis in the final standings, even though he also won one game.</p>
<p><a href="https://lichess.org/XhEzfx2y" class="btn btn-primary">View game on lichess &raquo;</a></p>
<p>I was ranked <a href="http://chess-results.com/tnr448826.aspx?lan=1&art=1&rd=5&fed=ENG">29th in the minor section</a> in the end, but without the full-point bye I would have been joint 33rd.</p>
<p>I thoroughly enjoyed the tournament and intend to play in more.</p>
<p><h3>Answers</h3></p>
<p>In game 1, queen takes h5! The h5 square is defended by g6, but if the g pawn takes the queen, then bishop to h7 is mate. If the g pawn doesn't take the queen, then
queen to either h7 or h8 is mate.</p>
<p>In game 4, king to d6 allows rook d7 mate.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/chess-tournament.html</link>
   <guid>http://incoherency.co.uk/blog/stories/chess-tournament.html</guid>
   <pubDate>Mon, 24 Jun 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>A Strange Chess Clock</title>
   <description><![CDATA[A chess clock is a device that has 2 countdown timers, used to place a limit on each player's thinking time in a chess game. White's clock is counting
down while it's white's turn. After white plays his move, he hits the clock, and his clock pauses, and black's clock now counts down. Once black
has played a move, he hits the clock, and white's clock resumes counting down, and so on.]]></description>
   <content:encoded><![CDATA[<p>A chess clock is a device that has 2 countdown timers, used to place a limit on each player's thinking time in a chess game. White's clock is counting
down while it's white's turn. After white plays his move, he hits the clock, and his clock pauses, and black's clock now counts down. Once black
has played a move, he hits the clock, and white's clock resumes counting down, and so on.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2214"><img src="https://img.incoherency.co.uk/2214/thumb"></a></p>
<p>My <a href="https://incoherency.co.uk/chess-clock">"Chess Clock"</a> is not like that, it's this:</p>
<p><link rel="stylesheet" type="text/css" href="https://incoherency.co.uk/chess-clock/css/chessboard-0.3.0.min.css">
<div id="chessclock"></div>
<script src="https://incoherency.co.uk/chess-clock/js/jquery-3.4.0.min.js"></script>
<script src="https://incoherency.co.uk/chess-clock/js/chessboard-0.3.0.min.js"></script>
<script src="https://incoherency.co.uk/chess-clock/js/fens.js"></script>
<script src="https://incoherency.co.uk/chess-clock/js/sans.js"></script>
<script src="https://incoherency.co.uk/chess-clock/js/embed.js"></script>
<script type="text/javascript">
EmbedChessClock('chessclock', '300px', 'https://incoherency.co.uk/chess-clock/img/chesspieces/wikipedia/{piece}.png');
</script></p>
<p><a class="btn btn-primary" href="https://incoherency.co.uk/chess-clock/">Chess Clock</a></p>
<p><a href="https://github.com/pwr22/">Peter</a> and I were talking at the weekend about deliberate misinterpretations of the phrase
"chess clock", and came across an interesting idea.</p>
<p>The idea is that we could use a chess board to encode the time of day. Each second in a 24-hour period
would be represented by a corresponding board position, and we just need some lookup tables to convert back and forth. But
it's easy to come up with 86400 unique random board positions, so let's try making the transitions from one position to the next
form a legal chess game! Then the board starts in the starting position at 00:00:00, and at 00:00:01 white plays the first move, at 00:00:02 black
responds, and so on, until 23:59:59, and the board is reset again at 00:00:00 the next day. We "just" need to find an 86400-turn game (or 43200 moves per side).</p>
<p>Unfortunately, a chess game is automatically drawn if there are 75 consecutive moves from both sides without a capture or pawn move, so that places
an upper bound on the possible length of a chess game. There are 96 possible pawn moves and 30 possible captures (notwithstanding
the fact that not all the pawn moves are possible without some pawn moves that are also captures, otherwise the pawns can't get
past each other). 126 * 75 = 9450 moves per side = 18900 positions. This is not enough to have one position for every second in the day,
although if we could reach just 4320 moves, that would be enough for one board position every 10 seconds.</p>
<p>I wrote <a href="https://github.com/jes/chess-clock/blob/master/longest-game">a Perl script</a> to depth-first search random moves trying
to find a game exactly 4320 moves long, and
ending with white delivering checkmate. That gives a unique board position for every 10 seconds throughout a 24 hour period.
We need to make sure to do pawn moves and piece captures to prevent the game from being drawn by the 75-move rule, and since there are only a small number of pawn moves and piece captures available,
we need to ration them carefully.
So there are just a few heuristics required:</p>
<p><ul>
<li>Don't do any pawn moves or piece captures, except on every 74th move</li>
<li>Don't stalemate or checkmate, except on the last move</li>
<li>Don't repeat any position</li>
</ul></p>
<p>Whether this algorithm finds a solution quickly depends on random chance. If it makes some unlucky choices early on, it tends
to get stuck. I just restarted it and tried again every time it got stuck, until I got a valid solution.</p>
<p>An amusing consequence of only allowing the pawns to move every 74 moves is that the first 74 moves just consist of moving the knights around the board
randomly, and shuffling the rooks back and forth, because all of the other pieces are hemmed in by pawns which aren't allowed to move:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2215"><img src="https://img.incoherency.co.uk/2215/thumb"></a></p>
<p>So to avoid this, I hardcoded the opening moves as <b>1. d4 Nf6 2. Bf4 d5</b>.
I also allowed any captures and pawn moves past move 4260 as this can't possibly prevent the game from running to full length, and actually helps with finding checkmate.</p>
<p>Having found a suitable 4320-move game, I encoded all 8640 positions in <a href="https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation">FEN</a>,
bundled them into a Javascript file, and used <a href="https://chessboardjs.com/">chessboard.js</a> to render them in the browser. So
that's our solution: we have a clock that represents the time of day using a chess position, to the nearest 10 seconds, and the transition from
each position to the next is a legal move, and the entire game is a legal game. You can <a href="https://incoherency.co.uk/chess-clock/">look
at the full Chess Clock page</a> if you want.</p>
<p>The game ends with <b>4320. a8=Q#</b> at 23:59:50 every day, before resetting to the starting position at 00:00:00. Most of the moves
are pretty bad, but no problem.</p>
<p><h3>Converting between different formats</h3></p>
<p>To make it easier to work with the Chess Clock positions, I made a tool to conveniently convert between Chess Clock time and ordinary time:</p>
<p><a href="https://incoherency.co.uk/chess-clock/converter.html"><img src="https://img.incoherency.co.uk/2217"></a></p>
<p><a class="btn btn-primary" href="https://incoherency.co.uk/chess-clock/converter.html">Chess Clock Time Converter</a></p>
<p>The board is editable (click and drag the pieces), and you can also edit the text boxes for the time, position ID, or FEN of the board position.</p>
<p>What we've got here is actually a bit more general than a clock. We can use the board positions to represent <i>any</i> number from 0 to 8639.
For example, you could use this to represent a PIN number (as long as it's less than 8640) by entering the PIN in the "position ID" field, and writing
down a drawing of the board position. To recover the PIN, you just need to recreate the board position in the Time Converter and read out the "position ID".</p>
<p>You could represent a 12-word <a href="https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki">BIP39</a> mnemonic seed for a Bitcoin wallet
by storing the 12 Chess Clock board positions corresponding to the BIP39 word numbers of the mnemonic seed. For example the word "coffee" is number 361
(indexed from 0), which is board position <b>1r2qb1r/pppkpppp/4n3/3pR3/1Q1PN3/2P5/PP2PPPP/1b1KNBnR</b>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2218"><img src="https://img.incoherency.co.uk/2218/thumb"></a></p>
<p>(And if you're interested in this sort of thing, you may enjoy my <a href="https://incoherency.co.uk/blog/stories/chess-steg.html">Chess Steganography</a> project).</p>
<p><h3>Learning to tell the time</h3></p>
<p>At first glance the positions appear completely random. How could you possibly learn to tell the time on this clock?</p>
<p>But remember that captured pieces never reappear (modulo pawn promotion), and pawns never move backwards. So we just need to memorise the order of captures and pawn moves, and then
we can get a coarse approximation of the time of day just by looking at where the pawns are and which pieces have been captured. Here's a guide
to telling the time to the nearest hour.</p>
<p>Starting from the top row, see if the next row could have happened (for example, if white's c pawn is on c2,
then <b>c3</b> couldn't have been played; if white's c pawn has gone then <b>c3</b> could have been played). If it's possible, move down a row and repeat.
If not, read off the time of the row you finished up on.</p>
<p><table border>
<tr><th>Time</th><th>Notable changes from 1 hour previous</th></tr>
<tr><td>00:00</td><td>-</td></tr>
<tr><td>01:00</td><td>white: c3,d4; black: d5</td></tr>
<tr><td>02:00</td><td>white c pawn has been captured</td></tr>
<tr><td>03:00</td><td>white: exf3; black: bxa6</td></tr>
<tr><td>04:00</td><td>white: g3; black: fxe6</td></tr>
<tr><td>05:00</td><td>black: g6,h6</td></tr>
<tr><td>06:00</td><td>white: h3; black: h5</td></tr>
<tr><td>07:00</td><td>white: h4; black: g5</td></tr>
<tr><td>08:00</td><td>white only has 1 rook</td></tr>
<tr><td>09:00</td><td>white: b4; black: a5</td></tr>
<tr><td>10:00</td><td>white b pawn has been captured; black: c6</td></tr>
<tr><td>11:00</td><td>black: g4</td></tr>
<tr><td>12:00</td><td>white: f4,f3; black: e5</td></tr>
<tr><td>13:00</td><td>white: a3; black: c5</td></tr>
<tr><td>14:00</td><td>white: f5, black: c4</td></tr>
<tr><td>15:00</td><td>black: e5</td></tr>
<tr><td>16:00</td><td>white: f6, white g pawn has been captured</td></tr>
<tr><td>17:00</td><td>white d pawn has been captured, white only has 1 f pawn</td></tr>
<tr><td>18:00</td><td>black g pawn has been captured</td></tr>
<tr><td>19:00</td><td>white f pawn has been captured, black only has 1 a pawn, black: c3</td></tr>
<tr><td>20:00</td><td>black: c2</td></tr>
<tr><td>21:00</td><td>black c and h pawns have been captured</td></tr>
<tr><td>22:00</td><td>black: e4</td></tr>
<tr><td>23:00</td><td>white: h5</td></tr>
</table></p>
<p><h3>Further work</h3></p>
<p>It might be cool to make a physical implementation of the clock, either using one of those <a href="https://squareoffnow.com/">Square Off</a> boards that can move
the pieces using magnets, or using a 6-axis robot like Chris Annin's 3d-printable <a href="https://github.com/Chris-Annin/AR2">AR2</a> to physically pick up the
pieces and move them, perhaps as some sort of art installation. Although, in either case, it might struggle to reset from the checkmate position to the starting
position in the requisite 10 seconds.</p>
<p>A "Chess Clock Chess Clock" would be funny. This would be like a traditional chess clock, in that it keeps track of the remaining time for 2 players,
except the time is displayed using the 4320-move "Chess Clock" game. It would probably have to count up instead of down, so that your time starts in
the starting position, and runs out when move 4320 is played. It could make one move every 100ms, for example, for a ~15-minute game.</p>
<p>If we wanted to encode the day of year in addition to the time, we'd need to have 365 unique games, with no common board positions between the games.
This is impossible as the first move for each colour only has 20 possibilities, so the maximum number of dates we could cover is 20. This could be solved
by choosing 365 of the <a href="https://en.wikipedia.org/wiki/Chess960">Chess960</a> starting positions, and then I think it should be <i>relatively</i> easy
to get 365 games with no common board positions.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/chess-clock.html</link>
   <guid>http://incoherency.co.uk/blog/stories/chess-clock.html</guid>
   <pubDate>Thu, 02 May 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to win at Scotland Yard</title>
   <description><![CDATA[I've been playing Scotland Yard recently. It's a board game in which one
player plays as "Mr. X", and the other players are all detectives, played on a map of London.
Mr. X moves in secret, and his goal is to evade capture for 24 turns, while the detectives' goal
is to capture him before 24 turns are up. It's a brilliant game.]]></description>
   <content:encoded><![CDATA[<p>I've been playing <a href="https://en.wikipedia.org/wiki/Scotland_Yard_%28board_game%29">Scotland Yard</a> recently. It's a board game in which one
player plays as "Mr. X", and the other players are all detectives, played on a map of London.
Mr. X moves in secret, and his goal is to evade capture for 24 turns, while the detectives' goal
is to capture him before 24 turns are up. It's a brilliant game.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2200"><img src="https://img.incoherency.co.uk/2200/thumb"></a></p>
<p>I wrote a <a href="https://github.com/jes/scotland-yard">Perl implementation</a> of the
game, including a basic AI to play as both Mr. X and the detectives.</p>
<p>Paul P. on boardgamegeek has written <a href="https://boardgamegeek.com/thread/102272/scotland-yard-basic-strategy">a strategy guide</a> for Scotland Yard from
experience and first principles, which is quite helpful. This post is about a more data-driven approach,
from tens of thousands of simulated games, to gather more information about the game.</p>
<p>Paul P. says Mr. X is likely to win ~30% of the time. I'd agree with this. That means if you're
playing as Mr. X, and you lose, it's not necessarily your fault. If you can win as Mr. X more
than 30% of the time, you're doing well. In the simulations, Mr. X won on average ~17% of the time,
but with the use of 2X cards he would have done better.</p>
<p>Throughout this post we'll talk about win probabilities: these are always from Mr. X's
perspective.
If the win probability of a certain configuration is 20%, that means Mr. X is 20% likely to win,
which means the detectives are 80% likely to win.</p>
<p><h3>1. Mr. X's starting station is critical</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/2190"><img src="https://img.incoherency.co.uk/2190/thumb"></a><br>
<i>Mr. X's winning chances from each starting station. The mean (grey) is 17%. Green is better, red is worse.</i></p>
<p>The single most significant factor that I could find to determine how likely Mr. X is to
win, from a dataset of 64k games, is the station he starts on.
From the worst starting station (146), Mr. X won only
6% of games. From the best starting station (166), he won 27%.</p>
<p><table border>
<tr><th>Starting station</th><th>Winning chances</th></tr>
<tr><td>166</td><td>26.9%</td></tr>
<tr><td>132</td><td>25.6%</td></tr>
<tr><td>127</td><td>22.8%</td></tr>
<tr><td>104</td><td>20.8%</td></tr>
<tr><td>35</td><td>20.7%</td></tr>
<tr><td>170</td><td>19.0%</td></tr>
<tr><td>78</td><td>18.6%</td></tr>
<tr><td>172</td><td>17.3%</td></tr>
<tr><td>51</td><td>16.8%</td></tr>
<tr><td>106</td><td>10.5%</td></tr>
<tr><td>45</td><td>8.7%</td></tr>
<tr><td>71</td><td>7.3%</td></tr>
<tr><td>146</td><td>6.2%</td></tr>
</table></p>
<p>There are 13 possible starting stations, and Mr. X is supposed to shuffle them and draw
one at random.</p>
<p>It's unfortunate that the starting station is selected at random, given that it is so critical.
I therefore propose a slight rule change:</p>
<p><blockquote>Before the detectives draw their stations at random, Mr. X is allowed to choose his
starting station freely from the set of Mr. X starting stations, instead of having to pick one
at random.</blockquote></p>
<p>You might think "but Mr. X will always pick station 166, and the detectives
will know that, so it won't work any more", but 
I tried a variant of the game where Mr. X always starts on station 166, and his winning
probability was only reduced from 27% to 26%, so if I were playing as Mr. X I would almost always
choose to start on station 166 or 132: even if the detectives know you've done this, you're still much
better off than choosing at random.</p>
<p>If you want to cheat, and you think you'll get away with it, you should start on
station 181. This is not among the set of allowable Mr. X starting stations in the official game,
but from station 181, in my simulations where Mr. X is allowed to start on <i>any</i> station,
Mr. X won 44% of games compared to the 27% of station 166. (But note that there were only about 200 simulated games for each of the 115 possible starting stations that are at least 2 hops away
from the nearest detective starting station, so this number probably has quite large error bounds).</p>
<p>I also tried to generate an alternative set of 13 starting stations which would provide
more balance, but I couldn't find 13 stations spread all across the board from which Mr. X
had reasonably similar chances of winning:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2196"><img src="https://img.incoherency.co.uk/2196/thumb"></a><br>
<i>Mr. X's winning chances from a wider set of possible starting stations.</i></p>
<p><h3>2. Some areas of the board are much worse for Mr. X than others</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/2165"><img src="https://img.incoherency.co.uk/2165/thumb"></a><br>
<i>Mr. X's winning chances from each visited station. The median (grey) is 35%. Green is better, red is worse.</i></p>
<p>Mr. X won 80% (!) of simulated games in which he managed to step on station 79 (the best
station). He won only 11% of games in which he stepped on station 7.</p>
<p>(It should be noted that Mr. X only managed to visit station 79 in less than 1% of games, whereas he
was forced onto station 7 in 10% of games.)</p>
<p>It doesn't <i>quite</i> follow that you should always head towards station 79, because your
real goal is to evade capture, not to visit station 79. But if you can step on station 79,
and there isn't currently a detective on an adjacent station, you probably have good chances
of winning.</p>
<p>I tried feeding this data back into the AI to see if it would play any better. I modified the
evaluation function to multiply the evaluation of each position by the prior win probability
of the station that Mr. X is on.</p>
<p><table border>
<tr><td colspan="2" rowspan="2"></td><td align="center" colspan="2">Detectives</td></tr>
<tr><td>With data</td><td>Without data</td></tr>
<tr><td rowspan="2">Mr. X</td><td>With data</td><td>15.6%</td><td>17.6%</td></tr>
<tr><td valign="center">Without data</td><td>21.0%</td><td>16.7%</td></tr>
</table></p>
<p>So it doesn't change his chances of winning by a lot. Surprisingly, Mr. X's best chance of
winning is when he is ignoring the "good" stations, and the detectives are going out of their
way to stop him from visiting them!</p>
<p>I'm not sure why the difference in winning chances is so small, when the observed difference
in winning chances between different stations is so high. Probably because the locations of the
detectives constrains Mr. X's movements so much that he has a lot of difficulty actually aiming
for the high-value stations.</p>
<p>The heatmap of winning chances probably serves best as a predictor of who is going to win,
rather than as a guide of where to move to. That is, if Mr. X is on a station coloured
bright green, he has a good chance of winning. But Mr. X has to primarily evade capture, and
only occasionally has the freedom to deliberately move towards the bright green areas.</p>
<p><h3>3. Where the detectives should move in the first 2 turns</h3></p>
<p>In the first 2 turns, the detectives have no information about Mr. X's location, other than
that he started at one of the possible starting stations. On turn 3, Mr. X has to reveal himself.
From the allowable starting stations, Mr. X can reach any station except: 2,5,18,19,121,150,162,175,182. (That is, every station except those is within 3 hops of at least one of the
allowable Mr. X starting stations).</p>
<p>So the goal of the detectives is to spend the first 2 turns to move to well-connected stations,
to minimise the maximum possible number of hops between the detectives and Mr. X. This
distance is minimised by moving as follows:</p>
<p><table border>
<tr><th>Starting station</th><th>Head towards any of</th><th>Max. hops to Mr. X</th></tr>
<tr><td>13</td><td>51,55,65,66,68,71,79,82,84,88,102,105,111,128,140</td><td>6</td></tr>
<tr><td>26</td><td>51,52</td><td>6</td></tr>
<tr><td>29,91,117</td><td>89</td><td>5</td></tr>
<tr><td>34</td><td>13,23,65,79</td><td>6</td></tr>
<tr><td>50</td><td>23,51,66</td><td>6</td></tr>
<tr><td>53</td><td>52,55,68</td><td>6</td></tr>
<tr><td>94</td><td>46,79</td><td>6</td></tr>
<tr><td>103,112</td><td>67</td><td>5</td></tr>
<tr><td>123,138</td><td>111,153</td><td>6</td></tr>
<tr><td>141</td><td>128,140</td><td>6</td></tr>
<tr><td>155</td><td>139,140,153</td><td>6</td></tr>
<tr><td>174</td><td>128</td><td>6</td></tr>
</table></p>
<p>In cases where the starting station has a single-hop connection to the designated destination,
you shouldn't use it! You should ensure that you take exactly 2 turns to move to the designated
station, so that you're well-positioned when Mr. X reveals himself on his
3rd turn.</p>
<p>In cases where two or more detectives have the same designated station (for example,
29, 91, and 117 all want to go to station 89), obviously only one can
actually go there. The detectives will have to discuss amongst themselves to find the best
allocation of detectives and stations.</p>
<p><h3>4. Playing a turn as Mr. X</h3></p>
<p>First, look at the set of possible moves you have. For each possible station, count the number of
hops to the nearest detective. Note that the nearest detective may be quite far away if the
station has bus or train connections. If a candidate station is only 1 hop from a detective
then you probably shouldn't move there, because there is a risk that the detective will step
on you next turn.</p>
<p>If you now have more than one candidate station that is more than 2 hops from the nearest
detective, consult the heat map of winning chances to decide which one is best, and try to
move to greener stations rather than redder ones.</p>
<p>If you have exactly one candidate station that is more than 2 hops from the nearest detective,
you should <i>probably</i> play that one. But note that if the detectives already know where you
are, they'll also know that you are likely to move to this station, so you may have better luck
sneaking past a detective in the opposite direction if a.) you are reasonably confident that
they know you only have one candidate station more than 2 hops from them, and b.) moving to
that candidate station while the detectives know where you are would result in them
"closing the net" over the next few turns.</p>
<p>If you have no candidate stations, then you're in trouble. It's probably time to spend a 2X
card if you have one. If you have one, do the same procedure again, but look 2 hops ahead
instead of just 1. You're looking for candidate stations that are at least 2 hops from the
nearest detective. Remember that in 2 hops you can move back to the station you started on.</p>
<p>If you have no candidate stations and no 2X cards, then you have to try to work out what the
detectives will do next turn, and move to a station that you think they will not move to.</p>
<p>Finally, if you're on a station that has bus, train, or ferry connections, consider using a black ticket
so that the detectives won't know how you travelled, particularly if the detectives know
which station you are on. You should never use a bus or train ticket unless doing so does not
reveal extra information about your location (for example, because you're about to reveal your
location anyway, or because your only legal move is a bus or train journey).</p>
<p><h3>5. Playing a turn as the detectives</h3></p>
<p>In the first 2 turns, you should move towards the well-connected stations as detailed
in the table above.</p>
<p>Once Mr. X has revealed himself on turn 3, you should start keeping track of the set of possible
stations that he could be on. There's no reason not to do this on a sheet of paper. After Mr.
X has moved, write down the set of possible stations he could be on. This is the set of all
stations that are reachable, via the ticket he used, from any of the stations he could have been
on last turn. After
the detectives have moved, you can cross off all of the stations that the detectives moved to,
because the game would have ended if Mr. X were there.</p>
<p>(If the set of possible stations gets too large to follow, then you've effectively lost
him: you should revert to the strategy
of moving to well-connected stations to try to close in again after he next reveals himself).</p>
<p>Think about all of the detective moves before moving any of the detectives. Sometimes you
have 2 detectives that can cover the same station, and it is important to decide which one
to send there based on which station you want the other one to cover.</p>
<p><h3>AI limitations</h3></p>
<p>The AI in my Perl implementation is a <a href="https://en.wikipedia.org/wiki/Minimax">minimax search</a> with
<a href="https://en.wikipedia.org/wiki/Iterative_deepening_depth-first_search">iterative deepening</a>, and a time limit of 30 seconds per turn.</p>
<p>30 seconds per turn is too long to do tens of thousands of games, so for the simulations I limited the search depth to only 1 ply: on each turn,
it considers all of the possible moves, evaluates the position, and then plays the move that is best, without any recursive searching of the opponent's responses.</p>
<p>The <a href="https://github.com/jes/scotland-yard/blob/2bfb79c8d935aca316001bed4b9efa2082d7a427/lib/ScotlandYard/AI.pm#L137">evaluation function</a>
is as follows:</p>
<p><ul>
<li>compute the shortest path from Mr. X to each detective</li>
<li>compute the number of possible stations that the detectives know Mr. X could be on</li>
<li>the score for Mr. X is the length of the shortest path to the nearest detective, plus 1/100th of the sum of the shortest paths to each detective, plus 1/100th of the number of possible stations</li>
</ul></p>
<p>Notably, this does not include any value for black tickets, which means Mr. X will always play a black ticket if it expands the set of possible stations he could be on,
regardless of whether that is actually a good use of the black ticket. It also does not include any value for 2X tickets, but this is "fine" because the AI doesn't
know how to use 2X tickets.</p>
<p>Since it's a zero-sum game, the detectives use exactly the same evaluation function as Mr. X does, but they have to evaluate it for each possible station Mr. X could be on
and assume the worst. The detectives team always had 4 detectives. When Mr. X is playing against 5 detectives he presumably has a harder time of it.</p>
<p>The biggest weaknesses of the AI used for the simulations are the lack of 2X tickets, and the limited search depth.</p>
<p><h3>Open questions</h3></p>
<p><ul>
<li>How significantly does the introduction of a 5th detective affect Mr. X's chances? Would giving Mr. X a 3rd 2X card keep the game more balanced with 5 detectives?</li>
<li>Assuming the detectives move according to the prescribed table, what are the optimal opening moves for Mr. X, from each possible Mr. X starting station, to maximise the minimum distance to the nearest detective upon revealing Mr. X on turn 3? (For 4 detectives, there are "16 choose 4" possible detective starting configurations, multiplied by 13 possible Mr. X starting stations, = 23660 possible combinations, which is large but brute-forceable)</li>
<li>Is it better for Mr. X to maximise the number of possible stations he could be on, or the number of hops to the nearest detective?</li>
</ul>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/scotland-yard.html</link>
   <guid>http://incoherency.co.uk/blog/stories/scotland-yard.html</guid>
   <pubDate>Thu, 04 Apr 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Puzzle Drawers</title>
   <description><![CDATA[For the last ~3 weeks I've been working on a chest of drawers. This is no ordinary chest of drawers, they are puzzle drawers.
The idea is that the puzzler is presented with one of the drawers already open, and the goal is to manipulate the chest into
a configuration where all of the drawers are closed. With a typical chest of drawers, this would be easy: just close the
drawer that is open. In the puzzle drawers, there are 3d-printed internal mechanisms linking the drawers together.]]></description>
   <content:encoded><![CDATA[<p>For the last ~3 weeks I've been working on a chest of drawers. This is no ordinary chest of drawers, they are puzzle drawers.
The idea is that the puzzler is presented with one of the drawers already open, and the goal is to manipulate the chest into
a configuration where all of the drawers are closed. With a typical chest of drawers, this would be easy: just close the
drawer that is open. In the puzzle drawers, there are 3d-printed internal mechanisms linking the drawers together.</p>
<p>Here's a picture of the finished drawers:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2166"><img src="https://img.incoherency.co.uk/2166/thumb"></a></p>
<p><h3>Assembly</h3></p>
<p>We start with an open chest:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2167"><img src="https://img.incoherency.co.uk/2167/thumb"></a></p>
<p>The chest is made from plywood, and is glued and screwed together.</p>
<p>There are two spring-loaded 3d-printed ratcheting teeth mounted inside the box. These will engage against sawtooth racks on the drawers.
You'll also notice some suspicious brown tape, this is teflon tape and is there to provide low-friction surfaces for the drawers to slide on.
It works well, the drawers slide much more smoothly on the teflon tape than they do directly against the wood.</p>
<p>The right-hand upper shelf is permanently fixed in place, but the left-hand upper shelf comes later.</p>
<p>Next we install the lower right-hand drawer:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2169"><img src="https://img.incoherency.co.uk/2169/thumb"></a></p>
<p>When the drawer is in the fully-closed position, the plastic bump on the edge of the drawer lifts the adjacent ratchet tooth. This will come in useful
later. There is also a large plastic plate that rises to the upper level. This will also come in useful later.</p>
<p>Next we have to install the lower-left drawer and the cross-shaped front assembly of the chest. I originally tried to make a video of myself
assembling the cabinet but it didn't go very well. Here's a still of me trying to get the lower-left drawer into place:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2168"><img src="https://img.incoherency.co.uk/2168/thumb"></a></p>
<p>The cross piece is made of two pieces of plywood with a lap joint.</p>
<p>Each of the drawers has a wooden part mounted on the side that knocks against the cross-shaped piece to stop the drawers from falling out.
This means the drawers need to be in place before the cross-shaped piece can go in. But the drawer fronts also mean that the cross-shaped
piece can't slide in after the drawers are already there, and the large plastic plate on the lower-right drawer means that the
shelf on the back of the cross-shaped piece can't be dropped in from above. Figuring out how to make this so that it can actually be assembled
was a puzzle all of its own!</p>
<p>The cross-shaped assembly is retained with screws, but not glue, so that it can be removed later for maintenance.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2171"><img src="https://img.incoherency.co.uk/2171/thumb"></a></p>
<p>With the lower drawers and the cross-shaped piece installed, we come to the upper level:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2170"><img src="https://img.incoherency.co.uk/2170/thumb"></a></p>
<p>The left-hand ratchet tooth is now engaged with its sawtooth rack, and the large plate from the right-hand lower drawer is aligned with the hole
in the left-hand shelf.</p>
<p>We can drop in the right-hand upper drawer and fit the gear:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2172"><img src="https://img.incoherency.co.uk/2172/thumb"></a></p>
<p>The spring-loaded gear is installed with the aid of an M10 bolt that threads directly into the plywood shelf. I wouldn't necessarily trust a wooden thread
like this to hold much load, but it only needs to hold the gear in place and seems sturdy enough. This photo also gives a good view of the plywood piece
that stops the drawer from coming out too far. We also see the other key mechanism inside the chest: when the lower-right drawer is pulled out about halfway, the lumpy part on the large plastic plate raises
the gear up so that it no longer engages with the toothed racks of the upper drawers.</p>
<p>The plastic gear turns directly on the smooth shaft of the bolt. I put a few drops of 3-in-1 on it, but if wear becomes a problem it could be sleeved with
a piece of steel or similar.</p>
<p>Now we can drop in the left-hand upper drawer:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2173"><img src="https://img.incoherency.co.uk/2173/thumb"></a></p>
<p>When both drawers are closed, and the gear is engaged, neither drawer can be opened. When the gear is disengaged, the drawers can move independently (for example,
one drawer can be pulled out). When the gear is re-engaged with one drawer opened, closing that drawer pushes the other drawer out.</p>
<p>The left-hand upper drawer has a plastic lump on it similar to the one on the right-hand lower drawer, to disengage the left-hand ratchet tooth:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2149"><img src="https://img.incoherency.co.uk/2149/thumb"></a></p>
<p>We now come to closing the lid. The lid is made of a board of laminated pine planks. I bought this ready-made from B&Q and just cut
it down to size. The lid has a plastic part with a hole in it, which lines up with a hole in the front assembly:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2174"><img src="https://img.incoherency.co.uk/2174/thumb"></a></p>
<p>A bluntened nail is inserted through these holes to keep the lid closed:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2175"><img src="https://img.incoherency.co.uk/2175/thumb"></a></p>
<p>And then the drawers can be closed, and the chest is complete:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2166"><img src="https://img.incoherency.co.uk/2166/thumb"></a></p>
<p>To reopen the lid, the top two drawers need to be opened, and then the nail needs to be pulled out, either by prying on it with a screwdriver, or (my preferred
method) pulling it out with a magnet.</p>
<p>The chest weighs 18kg in total. It can be lifted by the lid, but since the lid is only held down by a small 3d-printed piece, I prefer to lift it from
the bottom.</p>
<p><h3>Puzzle & Solution</h3></p>
<p>Now that we know how the chest is assembled, we can think about solving it. I recorded a video of myself solving the drawers, so you
can watch it if you want to see it in action, but there is no explanation in the video:</p>
<p><ul>
<li><a href="https://www.youtube.com/watch?v=GDeq6o76H2A">Video of puzzle drawers solution</a></li>
</ul></p>
<p>The initial configuration has the lower-left drawer pulled out:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2176"><img src="https://img.incoherency.co.uk/2176/thumb"></a></p>
<p>The right-hand ratchet is disengaged at this point, because the lower-right drawer is closed, but
the left-hand ratchet is preventing the lower-left drawer from closing. So we need to get the left-hand ratchet disengaged.</p>
<p>The left-hand ratchet disengages when the top-left drawer is pulled out about 1/4 of the way, but the top drawers won't move because they're geared together
and both closed. So we need to disengage the top gear.</p>
<p>We pull the lower-right drawer out until it meets resistance against the spring-loaded gear. This disengages the gear so that the top drawers can be moved:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2177"><img src="https://img.incoherency.co.uk/2177/thumb"></a></p>
<p>We now need to open one of the top drawers:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2178"><img src="https://img.incoherency.co.uk/2178/thumb"></a></p>
<p>With the top drawers now separated, we can close the lower-right drawer again. Remember the lower-right drawer needs to be closed in order to disengage
the right-hand ratchet on the lower-left drawer.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2179"><img src="https://img.incoherency.co.uk/2179/thumb"></a></p>
<p>Now we need to position the top-left drawer about 1/4 of the way out so that the left-hand ratchet is disengaged. This will also result in some movement of
the top-right drawer but we don't mind at this point.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2180"><img src="https://img.incoherency.co.uk/2180/thumb"></a></p>
<p>At this point both of the ratchets are disengaged, and the lower-left drawer can be closed.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2181"><img src="https://img.incoherency.co.uk/2181/thumb"></a></p>
<p>But we still have the top two drawers geared together, so it is impossible to close more than one at any time. To solve this, we again need to pull out the
lower-right drawer until it disengages the top gear.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2182"><img src="https://img.incoherency.co.uk/2182/thumb"></a></p>
<p>Then we can close both of the top drawers:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2183"><img src="https://img.incoherency.co.uk/2183/thumb"></a></p>
<p>Finally, we close the bottom-right drawer and the puzzle is solved.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2184"><img src="https://img.incoherency.co.uk/2184/thumb"></a></p>
<p><h3>More</h3></p>
<p>Several people suggested that puzzle drawers could be a good addition to an <a href="https://en.wikipedia.org/wiki/Escape_room">escape room</a>. I think
this might work well if the design were modified so that the goal is to <i>open</i> a particular drawer rather than to close it, so that a key or a clue
could be hidden inside that drawer. Probably this would be as simple as reversing the ratchets on the lower-left drawer. Come to think of it, I wish
I'd done that in the first place.</p>
<p>One thing I really hate about certain types of drawers is when they don't open far enough to be able to see the things at the back of the drawer. Unfortunately
the puzzle drawers have hardware mounted on the sides which we don't want the puzzler to be able to see, so the movement of the drawer must be constrained to
only 50% of the length of the drawer (and, in practice, slightly less). This is a problem. For this reason I have mounted the "backs" of the drawers about 3/4
of the way along, instead of all the way at the back. This has the effect of shortening the drawer so that things inside can't roll back as far. I've not
yet reached a conclusion as to whether I prefer a deep cabinet with deep drawers which I can't see the back of, or a deep cabinet with short drawers.</p>
<p>A week ago I posted <a href="https://www.youtube.com/watch?v=za7VGjRAmvA">a video showing the mechanisms working for the first time</a>, and at that point
the top gear didn't engage very reliably. At 00:25 in the video you can hear a "click". I had anticipated this problem, and beveled the bottom edge of the
gear to try to avoid it, but what I hadn't realised is that beveling the bottom edge of the gear doesn't actually make it any easier to engage at all.</p>
<p>Old gear on the left, redesign on the right:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2162"><img src="https://img.incoherency.co.uk/2162/thumb"></a></p>
<p>The width of the teeth at any given radius from the centre is still exactly the same as it would be if there were no bevel (left). I solved this (right) by tapering the
size of the teeth towards the bottom, instead of just chopping them off at a taper. The gear design library that I use in OpenSCAD doesn't support this,
so I created the tapered gear by stacking a large number of very thin gears, of different sizes, on top of each other at 0.2mm increments. Since I 3d print at a 0.2mm layer
height, this is functionally equivalent to a smooth taper.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/puzzle-drawers.html</link>
   <guid>http://incoherency.co.uk/blog/stories/puzzle-drawers.html</guid>
   <pubDate>Sun, 17 Mar 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The Wheatstone Cryptograph</title>
   <description><![CDATA[A few weeks ago I came up with an idea for a simple encryption device, then found that it had already been invented
by Sir Charles Wheatstone around the
1860s. I ended up designing and 3d printing a replica of Wheatstone's cryptograph.]]></description>
   <content:encoded><![CDATA[<p>A few weeks ago I came up with an idea for a simple encryption device, then found that it had already been invented
by <a href="https://en.wikipedia.org/wiki/Charles_Wheatstone">Sir Charles Wheatstone</a> around the
1860s. I ended up designing and 3d printing a replica of Wheatstone's cryptograph.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2134"><img src="https://img.incoherency.co.uk/2134/thumb"></a></p>
<p><h3>The principle</h3></p>
<p>My idea was to have 2 wheels geared together, one with 26 teeth
and one with 27 teeth. Each tooth would be labelled with a letter of the alphabet (with an extra character on the
27-tooth gear). The letters on the 26-tooth gear would correspond to the plaintext, and the letters on the 27-tooth
gear would correspond to the ciphertext. A message is encoded by rotating the plaintext wheel clockwise until the
desired letter is reached, and then writing down the letter displayed on the ciphertext wheel. One complete turn
of the 26-tooth plaintext wheel results in 1 tooth less than one complete turn of the 27-tooth ciphertext wheel,
which means the ciphertext alphabet gets shifted along by one place for every rotation of the wheel.</p>
<p>My first attempt was simply 2 gears with letters directly on the teeth:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2107"><img src="https://img.incoherency.co.uk/2107/thumb"></a></p>
<p>To encrypt a message, you simply turn the left gear until the arrow points at your letter, and then write down the
letter indicated on the right gear. Decryption is the same, but with the gears swapped. In order to select a different key,
you would obviously need to print a gear with different labels on it.</p>
<p><h3>Wheatstone's device</h3></p>
<p>It occurred to me that perhaps I'm not the first person to come up with this idea, so I searched online
for various combinations of words like "26 tooth 27 tooth cipher" and came across
<a href="http://www.jproc.ca/crypto/wheatstone.html">Jerry Proc's page on the Wheatstone cryptograph</a>, featuring
this device:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2132"><img src="https://img.incoherency.co.uk/2132/thumb"></a></p>
<p>(more photos and description on Jerry's page).</p>
<p>Wheatstone connected the 26-tooth gear to the ciphertext hand, and the 27-tooth gear to the plaintext hand. By the
<a href="https://en.wikipedia.org/wiki/Pigeonhole_principle">pigeonhole principle</a>, it is not possible to unambiguously
encode every possible letter from the plaintext disc (27 possibilities map to 26 possibilities). This is solved by putting a
letter "Q" or "X" in between doubled letters so
that at any given state there are only 26 possible plaintext characters
("HELLO" becomes "HELXLO").</p>
<p>The outer ring of letters is fixed in place, while the inner ring is a piece of cardboard, designed to have a scrambled
alphabet
written in pencil. (I understand that the original device had 26 removable letters that slot into holes, but
they are easily lost over time and have been replaced with the cardboard ring).</p>
<p>The large hand is fixed to the shaft that it rotates on, while the small hand is only loosely clamped to its shaft
by spring tension (provided by the large slit in it). The small hand can therefore be rotated independently
of the large hand in order to synchronise the two hands.</p>
<p>Inside, there are 3 gears:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2133"><img src="https://img.incoherency.co.uk/2133/thumb"></a></p>
<p>This is a surprising arrangement and at first glance I was surprised that it could even work.
It is actually impossible to design gears
that have a different number of teeth, mesh perfectly against a common pinion, and rotate around the same centre. The tooth
profile on the pinion dictates the tooth profile on the other 2 gears, and for a given tooth profile, changing the tooth count
will change the diameter of the gear, which means the centre of rotation needs to move slightly in order to
keep the gears meshing correctly. However, 26 and 27 are close enough tooth counts that it can be made to work plenty well enough.
Quite clever really. Each gear has a shaft that sticks up through the top of the device, concentrically, for the hands to
attach to, just like on a clock.</p>
<p>Interestingly, a <a href="https://en.wikipedia.org/wiki/Wadsworth%27s_cipher">similar device</a> was actually invented
about 50 years earlier, by Decius Wadsworth. I couldn't find any good photographs of Wadsworth's device, but there is this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2137"><img src="https://img.incoherency.co.uk/2137/thumb"></a></p>
<p>from <a href="https://www.nsa.gov/Portals/70/documents/news-features/declassified-documents/friedman-documents/patent-equipment/FOLDER_515/41788379082740.pdf">a 1949 NSA document</a> (<a href="https://incoherency.co.uk/interest/wadsworth.pdf">mirrored</a>), released to the public in 2014.</p>
<p><h3>Cryptanalysis</h3></p>
<p>I ended up exchanging some emails with <a href="http://ciphermachines.com/">Ralph Simpson</a>, the owner of the Wheatstone
cryptograph pictured
above and on Jerry's page. Ralph directed me to some good resources on breaking the Wheatstone cryptograph:</p>
<p><ul>
<li><a href="https://babel.hathitrust.org/cgi/pt?id=mdp.39015004979913;view=1up;seq=340">Macmillan's Magazine, 1871</a> (starting on page 335) (<a href="https://incoherency.co.uk/interest/macmillan-magazine-1871.pdf">mirrored</a>) (99 MB)</li>
<li><a href="https://www.nsa.gov/Portals/70/documents/news-features/declassified-documents/friedman-documents/publications/ACC15281/41785109082412.pdf">The Friedman Lectures on Cryptology</a> (starting on page 139) (<a href="https://incoherency.co.uk/interest/friedman-cryptology.pdf">mirrored</a>) (11 MB)</li>
<li><a href="http://www.campx.ca/Several_Machine_Ciphers.pdf">Several Machine Ciphers and Methods for their Solution</a> (section II) (<a href="https://incoherency.co.uk/interest/several-machine-ciphers.pdf">mirrored</a>) (42 MB)</li>
</ul></p>
<p>The latter being the most detailed.</p>
<p>To have a go at cracking it myself, I wrote a program to select a random copyright notice from <tt>/usr/share/doc</tt>, encrypt it with a random key, and then print out
the ciphertext. I was able to crack all 4 that I tried, but only because I knew what some of the plaintext of a copyright notice looks
like. I then tried selecting random files that aren't copyright notices, from <tt>/usr/share/doc</tt>, but I haven't yet been able
to crack the only one I've tried.</p>
<p>There are a few observations that help in breaking the Wheatstone cryptograph:</p>
<p>The state of the device resets to the starting state after 26 revolutions of the large hand. If characters are selected from the
plaintext wheel uniformly at random, we can expect to complete 1 revolution of the large hand every other letter, which means we can
expect the device state to reset after 52 letters. Friedman notes that in practice this is closer to 50 letters due to
non-uniform letter distribution.</p>
<p>If we see a doubled letter in the ciphertext (e.g. <tt>TT</tt>) then we know that this corresponds to 2 letters in the plaintext
that are adjacent in the alphabet, but in reverse order (e.g. <tt>ED</tt>). This is because moving from <tt>E</tt> to <tt>D</tt>
means turning the large hand through 26 steps, which is a complete revolution of the small hand, leaving it on the same letter it
started on.</p>
<p>If we see a doubled letter in the ciphertext with another letter in between (e.g. <tt>TLT</tt>) then we know that in this case as
well, the two <tt>T</tt>'s correspond to adjacent-but-reverse-order letters on the plaintext disc (e.g. <tt>TLT</tt> could be
<tt>EAD</tt>). Where the same letter appears in the ciphertext with <i>n</i> letters in between (e.g. <tt>TLFXT</tt>, <i>n = 3</i>) then we know that the repeated letter corresponds to letters in the plaintext that are in reverse order, with a maximum of
<i>n-1</i> other letters between them (e.g. <tt>TLFXT</tt> could <i>not</i> be <tt>HOARD</tt> because <tt>H</tt> and <tt>D</tt>
are too far apart, but it could be <tt>STAIR</tt> because <tt>S</tt> and <tt>R</tt> are close and in reverse order).</p>
<p>It would be more secure if the plaintext disc were scrambled in addition to the ciphertext disc, as this would not allow the
attacker to immediately start placing derived key characters in the right places relative to each other. It doesn't completely
save the cipher, however, as Friedman has a method for cracking it regardless (although I don't fully understand it).
Wadsworth actually figured this out despite having invented his device 50 years earlier, and on Wadsworth's device it was
possible to scramble both discs.</p>
<p>If the cryptograph were modified such that the plaintext disc were scrambled and the ciphertext disc were in alphabetical order
(or, more generally, if the plaintext disc is scrambled and the ciphertext disc is merely known to the attacker) then the
cipher is very weak indeed. An attacker who knows the contents of the ciphertext disc has all the information he needs to
recreate the movements of both hands. He can label his plaintext disc arbitrarily, and decrypt the message as usual. The
resulting "plaintext" thus derived only differs from the real plaintext by the labelling of the plaintext characters, and is
therefore solved as a simple substitution cipher.</p>
<p><h3>3d printed replica</h3></p>
<p>I spent some time modelling a 3d-printable replica of Wheatstone's device, mostly in FreeCAD but the gears and letters were done in
OpenSCAD:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2136"><img src="https://img.incoherency.co.uk/2136/thumb"></a></p>
<p>If you want to print your own, you can download the STL files: <a class="btn btn-primary" href="https://incoherency.co.uk/interest/wheatstone.tar.gz">Download STL files</a> (2.7 MB).</p>
<p>You'll want 2 small self-tapping screws to hold the gear cover on. And if you want the letters to be retained magnetically (and you do, because they're very small, light, and easily lost) then
you'll want 106 tiny disc magnets. I used 2mm x 0.5mm, but up to 2.5mm x 1mm would work. Make sure you glue them all with the magnetic poles in the same orientation so that they don't repel the letters away. You also might consider printing the letters
a couple of percent under-size if you intend to paint them.</p>
<p>Some of the details on Wheatstone's device are very small. I tried to print the gears at the original scale, but my 3d printer
just can't make accurate teeth at the required precision, so I doubled the size of the gears. There is also a very fine
thread on the top of the large-hand shaft, on to which a decorative nut is threaded to keep the large hand in place. Even on
my over-sized imitation, the top of the shaft is only 3mm wide. There was no way I was going to be able to print a thread this
small so I didn't even try, I just made the hand a tight push-fit on to the square end of the shaft.</p>
<p>The strange-looking bend in the large hand is just there to allow the small hand to pass underneath.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2118"><img src="https://img.incoherency.co.uk/2118/thumb"></a></p>
<p>I put a tiny magnet in the bottom of each letter, and a tiny magnet in the base in the place of each letter, so that the letters
remain in place even when held upside down, but can easily be removed and reordered.</p>
<p>I spent quite a long time priming and sanding the top surfaces of the cryptograph so that it looks nice and smooth when painted.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2127"><img src="https://img.incoherency.co.uk/2127/thumb"></a></p>
<p>The gear cover has that fun hexagon pattern so that you can look in the bottom and watch the gears moving. This is accomplished
by slicing a solid part for 3d printing with 0 top layers and 0 bottom layers, so that the infill pattern is visible. It can't
be used for all parts, but where it can it's a nice effect.
I didn't bother priming and sanding the bottom surface, but it looks pretty bad where it didn't stick to the print bed
properly, so perhaps I should have:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2130"><img src="https://img.incoherency.co.uk/2130/thumb"></a></p>
<p>The letter tiles are painted white, with a permanent marker rubbed over the raised parts to make the letters black.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2131"><img src="https://img.incoherency.co.uk/2131/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/wheatstone-cryptograph.html</link>
   <guid>http://incoherency.co.uk/blog/stories/wheatstone-cryptograph.html</guid>
   <pubDate>Fri, 15 Feb 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Telescope tracking with software auto-guiding</title>
   <description><![CDATA[The Earth rotates around its axis at a
rate of ~360&deg;/day, or ~15&deg;/hr (it's actually slightly slower than this because "1 day" is the amount of time it takes
for the sun to come around again, but we are also moving around the sun, so we don't need to rotate a full 360&deg; per day).
When zoomed in with a field-of-view only 0.25&deg; wide, objects that are not very close
to the North star appear to move quite quickly across the frame. For this reason, my telescope control software
continually updates the coordinates that it wants to
point at,
in order to keep the scope pointed at the same part of the sky.]]></description>
   <content:encoded><![CDATA[<p>The Earth rotates around its axis at a
rate of ~360&deg;/day, or ~15&deg;/hr (it's actually slightly slower than this because "1 day" is the amount of time it takes
for the sun to come around again, but we are also moving around the sun, so we don't need to rotate a full 360&deg; per day).
When zoomed in with a field-of-view only 0.25&deg; wide, objects that are not very close
to the North star appear to move quite quickly across the frame. For this reason, my telescope control software
<a href="https://github.com/jes/pikontroll/blob/master/pikontrolld#L245">continually updates the coordinates</a> that it wants to
point at,
in order to keep the scope pointed at the same part of the sky.</p>
<p>But any error at all in any part of
the axis alignment or base levelling will cause the image to drift away over time. Manual intervention is required to periodically
re-centre the object. This post is about how I fixed this in software by auto-guiding the scope based on the image from the
camera.</p>
<p><h3>1. Tracking error</h3></p>
<p>Before thinking about auto-guiding we should try to characterise the sources of error that already exist.</p>
<p><h4>1.1. Error shown in the images</h4></p>
<p>With the tracking turned off, the target object is not in the frame for very long:</p>
<p><a id="fig1" href="https://img.incoherency.co.uk/2081"><img src="https://img.incoherency.co.uk/2081"></a><br>
<i>Fig. 1: Orion nebula with tracking off, 60 seconds.</i></p>
<p>In 60 seconds, the subject moved almost all the way across the frame! With tracking turned on, we do better:</p>
<p><a id="fig2" href="https://img.incoherency.co.uk/2082"><img src="https://img.incoherency.co.uk/2082"></a><br>
<i>Fig. 2: Orion nebula with tracking on, 4 minutes (cf. <a href="#fig1">fig. 1</a>).</i></p>
<p>It's still in the frame after 4 minutes, although it is not in the same place, and it would eventually drift out.</p>
<p>I manually checked the pixel coordinates of the main star in the nebula for each frame in both of these timelapses to show how the
image moves in the frame over time. The "tracking error" value on the <i>y</i> axis is the radius from the starting location, i.e.
<i>sqrt(xoffset<sup>2</sup> + yoffset<sup>2</sup>)</i>.</p>
<p><a id="fig3" href="https://img.incoherency.co.uk/2083"><img src="https://img.incoherency.co.uk/2083"></a><br>
<i>Fig. 3: Tracking error with tracking off versus on.</i></p>
<p>(I scaled the original 2592x1944 images down to 500x375 to make them easier to work with, so the pixel distances
reported here are also scaled down relative to the full-size images).</p>
<p>We can see that the "no tracking" case slides away quite quickly, while the "tracking" case slowly drifts away.</p>
<p><h4>1.2. Error caused by the motors</h4></p>
<p>While the slow drift is a result of mechanical misalignment (of the rotation axes or the base or both), there is also a small
amount of "jitter". This jitter is caused by not being able to place the motors at exactly the location we want to place them.
Partly because the step resolution is not sufficiently fine-grained, and partly because the motor undershoots or overshoots the
target and it takes time to correct that.</p>
<p>I didn't have any data for the tracking error from the motors, so I set the telescope up on my desk in the daytime and configured
it
to track the Orion nebula for 5 minutes in order to gather data on how far away the actual motor positions are from
the targeted positions.</p>
<p><a id="fig4" href="https://img.incoherency.co.uk/2084"><img src="https://img.incoherency.co.uk/2084"></a><br>
<i>Fig. 4: Tracking error of motor step counts.</i></p>
<p>There are two effects demonstrated here. Looking particularly at the azimuth motor:</p>
<p>1.) There is a non-zero steady-state error of an average of 5.1 steps. I think this is because I've recorded the difference between the
instantaneous desired target position and the current position at the same instant, and it takes time for the motors to move to
the new target. We could correct for this by simply adding the mean tracking error to the target step count, but since this
value doesn't cause either jitter or drift, it's not a big deal.</p>
<p>2.) There is jitter around the mean error. The standard deviation (i.e. the variation that ~2/3 of data points lie within) is 1.4
steps. This is remarkably good given that the motor
controller only tries to <a href="https://github.com/jes/pikontroll/blob/master/pikontroll.ino#L220">target to the nearest 4
steps</a>! These are DC motors, not steppers, so anything smaller than that is too hard to hit exactly. The reason
the standard deviation is better than 4 steps is because the motion (over a short time period) is all in the same direction, so
the motor just has to periodically spin up and move roughly the same number of steps in roughly the same direction. When it
overshoots the target point, it just waits, and the error reduces over time on its own as the desired target point
changes.</p>
<p>If the altitude motor is at 0&deg; (i.e. the telescope is parallel to the ground, where the azimuth motor has the largest
effect), then a deviation of 1.4 steps on the azimuth
axis would manifest as about 4 pixels of deviation on the <i>x</i> axis of the output image (at 500x375).</p>
<p>The mean tracking error observed in the image was 42 pixels, with standard deviation of 18 pixels. So error from imprecise motor
positioning was not the dominant force even over only a 5-minute time period. That's good, because it's annoying and expensive to
upgrade the motors, but it's fun and cheap to write auto-guiding software!</p>
<p><h3>2. Auto-guiding</h3></p>
<p>The idea of auto-guiding is that we want software to continually monitor the image from the camera, and as it starts to drift
in one direction or another, we want it to adjust the trim on the motors to keep the image in the same place. This may sound like
a bodge, but it is a legitimate solution and is used even on top-end telescopes. Admittedly, top-end telescopes
track better <i>without</i> auto-guiding than mine is ever likely to track even with auto-guiding. But that's not the point.</p>
<p>From what I've been able to gather, auto-guiding generally works by having a small telescope mounted on the side of the main telescope, with the camera feed going to some auto-guiding software, which needn't have any relationship at all with the
main telescope software, it just needs to be able to adjust the motors.
You then tell the auto-guiding software which star you want it to monitor, and it will monitor a small window of pixels
around that star. As the star drifts, the software gives commands to the motors to tell
them what to do, aiming to direct the star back
to where it started. It is even possible to use this system to correct errors smaller than a single pixel by examining how the
brightness drops off towards the edges of the star.</p>
<p>The reason to use a separate telescope for guiding is because the auto-guider needs to take images quite often, while the main telescope
might be taking long exposures. You want the auto-guider to keep the image centred for the duration of the long exposure, so
it needs to be able to examine pictures more often than the main telescope can supply them.</p>
<p>I don't want to mount a separate telescope on the side, and my telescope doesn't take exposures longer than 1 second anyway, so
I am planning to auto-guide using the images from the main telescope.</p>
<p><h4>2.1. Detecting the position of a star</h4></p>
<p>So our first problem is we need an algorithm that, given an image and a window of pixels to examine, can identify the exact
location of the star within the window of pixels.</p>
<p>It's always best to start with the stupidest thing that can possibly work, so my first thought was that we can just weight the
pixels in the window by brightness, and then select the mean pixel location. This actually
works adequately as long as the star is sufficiently bright relative to the background noise. It works slightly better
if you weight the pixels by the square of the brightness. We could probably do even better if we detected the background noise
level (perhaps the median brightness? or the 25th percentile brightness?) and subtracted it away, but I've not felt the need to
do so.</p>
<p>The algorithm I use just looks like this:</p>
<p><pre><code>xsum = 0, ysum = 0, total = 0
for y = 0 to height:
    for x = 0 to width:
        k = brightness(x, y) * brightness(x, y)
        xsum += x * k
        ysum += y * k
        total += k
starlocation = (xsum / total, ysum / total)</code></pre></p>
<p>I wrote a small program to test this algorithm. It draws a green box around the window of pixels that it is examining,
and a small red box (slightly hard to see) around the detected centre of the star:</p>
<p><a id="fig5" href="https://img.incoherency.co.uk/2089"><img src="https://img.incoherency.co.uk/2089"></a><br>
<i>Fig. 5: Auto-guiding test.</i></p>
<p>As you can see, the position of red box is spot on in every frame.</p>
<p>The coordinates of the green box are specified manually for the first frame, and then for every subsequent frame it centres the green
box around where the star was detected to be in the previous frame.</p>
<p>The most important parameter is the size of the green box. If it is set too large the jitter can cause it to encompass additional
stars, and then the location of the mean-square-brightness no longer corresponds to just the location of the star we want to track,
so the guide position can change over time. Note how the red box starts out in the centre of the star and then moves away
when the other star comes into the window:</p>
<p><a id="fig6" href="https://img.incoherency.co.uk/2098"><img src="https://img.incoherency.co.uk/2098"></a><br>
<i>Fig. 6: Auto-guiding test with window too large (cf. <a href="#fig5">fig. 5</a>).</i></p>
<p>We might be able to use some sort of clustering algorithm to throw away all but the central brightness peak, but I've not
yet felt the need to do this either.</p>
<p>If the window size is too small the star could jitter out of the window and we could lose the auto-guiding entirely. This is much
worse than what happens if the window is too large. I did try using the
entire image as the window and it still seems to basically track the same point relative to the stars, so if in doubt it is
always better to set the window too large than too small.</p>
<p>A good side effect of the existence of this test program is that we can now use it to <a href="https://incoherency.co.uk/blog/stories/exposure-stacking.html">align individual exposures
for stacking</a>! I haven't actually done that yet, but it should be as easy as taking the output star coordinates for each
frame
and writing a small shell script around imagemagick.
That would remove the requirement for manual layer alignment, which is the most time-consuming part of my exposure
stacking workflow.</p>
<p><h4>2.2. Guiding the scope</h4></p>
<p>Now that we can reliably detect a star in a user-defined window, we can compute the pixel distance between where the star is now
and where it was when we started, and therefore how far we need to move it back. We then need to convert this pixel distance in
to a step count in order to adjust the trim on the motors and keep the scope guiding correctly.</p>
<p>This is actually harder than it sounds because:</p>
<p>a.) It takes time for the trim commands to get to the scope, and we may get extra frames back from the camera that were taken
with the old trim value. We don't want to keep adding offsets to the trim while this is happening, else we'll overshoot the
target position.</p>
<p>b.) The number of steps per pixel is not constant on the azimuth axis. When the altitude motor is at 0&deg; (horizontal), each
step moves the image sideways by about 3px (at 500x375), but this distance gets smaller as the altitude motor is raised. When the
altitude motor is at 90&deg; (vertical), each step doesn't move the image sideways at all! It only rotates it around the centre.</p>
<p>c.) The scope is jittering in addition to drifting. We want to average out the effects of the jitter so that we aren't constantly
banging the motors back and forth.</p>
<p>This sounds like a job for a <a href="https://en.wikipedia.org/wiki/PID_controller">PID controller</a>, although I haven't yet
implemented one. I have <a href="https://github.com/jes/RPi_Cam_Web_Interface/blob/master/www/js/pikontroll.js#L444">some hairy
ad-hoc javascript</a> based around some guessed magic numbers, like the minimum number of data points required, worst-case round-trip
time between adjusting trim and seeing the adjustment in the images, maximum age of data point for calculating position, and
number of steps per pixel. Maybe I'll write a PID controller one day.</p>
<p><h4>2.3. User interface</h4></p>
<p>Aside from auto-guiding, I've recently added various other pieces of real-time image processing to
<a href="https://github.com/jes/RPi_Cam_Web_Interface">my fork of RPi Cam Web Interface</a>. Mostly this is
in aid of amplifying the brightness of very dim objects, but it was a convenient place to add the auto-guider. Happily,
the same image processing that makes the star easier to see for the operator also makes the star easier to see for the auto-guider,
although it may compromise sub-pixel precision if more pixels are clipped to maximum brightness.</p>
<p><a id="fig7" href="https://img.incoherency.co.uk/2087"><img src="https://img.incoherency.co.uk/2087"></a><br>
<i>Fig. 7: User interface with auto-guiding enabled.</i></p>
<p>The checkbox at bottom left enables auto-guiding. Once it is checked, the mouse pointer turns into a crosshair and you have to
click on a star in the image. This places the small blue circle. The blue circle never moves, and only serves to indicate the
position that the auto-guider wants to move the star on to. The green box (sized according to the slider next to the
checkbox) indicates the size and location of the window in which the auto-guider is looking for the star. The red circle
indicates the current detected location of the star.</p>
<p><h3>3. Measuring the improvement</h3></p>
<p>Last night I managed to get about 15 minutes of uninterrupted timelapse of the Orion nebula before it became too cloudy.
This was an excellent opportunity to try out the auto-guider:</p>
<p><a id="fig8" href="https://img.incoherency.co.uk/2088"><img src="https://img.incoherency.co.uk/2088"></a><br>
<i>Fig. 8: Orion nebula with tracking and auto-guiding, 15 minutes (cf. <a href="#fig2">fig. 2</a>).</i></p>
<p>It works! The jitter is still there, but it's a substantial improvement on what we had before with un-guided tracking because the image no longer drifts in
the frame over time.</p>
<p>I manually recorded the trim settings while it was auto-guiding:</p>
<p><a id="fig9" href="https://img.incoherency.co.uk/2091"><img src="https://img.incoherency.co.uk/2091"></a><br>
<i>Fig. 9: Trim settings while auto-guiding.</i></p>
<p>(I didn't record this very often, so high-frequency components, i.e. over-corrections, will be missing. I should
add some automated logging).</p>
<p>We can see that the auto-guider has adjusted the altitude motor down over time, relative to where it would be from tracking
alone, and it has adjusted the azimuth motor towards the right over time, relative to where it would be from tracking alone.
That probably means the telescope was out of level, with the top leaning towards the left.
The
azimuth motor ended up trimmed by more than 50 steps away from where it started, which would manifest as a difference of about
140 pixels on the <i>x</i> axis of the image (at 500x375).</p>
<p>I used the auto-guiding test program to label the centre of the star in each frame, and produced an updated version of
<a href="#fig3">figure 3</a> with the
auto-guiding data included:</p>
<p><a id="fig10" href="https://img.incoherency.co.uk/2092"><img src="https://img.incoherency.co.uk/2092"></a><br>
<i>Fig. 10: Tracking error with tracking off versus on versus auto-guided (cf. <a href="#fig3">fig. 3</a>).</i></p>
<p>And indeed the slow drift over time from the "Tracking" case is gone, we just have some sources of jitter around the
centre point. With the slow drift gone, we should now be able to track the same star all night long (modulo cloud cover), with no
manual adjustment
required. This is a great success.</p>
<p>We can also plot the mean (in the main bars) and standard deviations (in the "error bars") of the tracking errors
in the 3 different cases:</p>
<p><a id="fig11" href="https://img.incoherency.co.uk/2093"><img src="https://img.incoherency.co.uk/2093"></a><br>
<i>Fig. 11: Comparison of tracking error distributions (smaller is better).</i></p>
<p>Also note that the error for the "NoTracking" and "Tracking" cases would presumably increase over time, and that the
"Tracking+Guiding"
data is based on a much longer timelapse. So probably this error distribution is understating how much of an improvement the
auto-guider is.</p>
<p><h3>4. Unaligned exposure stacking</h3></p>
<p>Just for fun I tried stacking the exposures together without any alignment, to
see what they look like in the three different cases. I also haven't subtracted any dark frames, so the background gets quite
bright.</p>
<p>First we have no tracking:</p>
<p><a id="fig12" href="https://img.incoherency.co.uk/2094"><img src="https://img.incoherency.co.uk/2099"></a><br>
<i>Fig. 12: Unaligned stack of 13 frames with tracking off.</i></p>
<p>It's just a bunch of separate dots.</p>
<p>With tracking on it's a bit better:</p>
<p><a id="fig13" href="https://img.incoherency.co.uk/2095"><img src="https://img.incoherency.co.uk/2100"></a><br>
<i>Fig. 13: Unaligned stack of 50 frames with tracking on (cf. <a href="#fig12">fig. 12</a>).</i></p>
<p>It still clearly moved, but the basic shape is there. (I don't know why the background is so much darker here;
possibly these images were taken with lower ISO setting).</p>
<p>With auto-guided tracking it's even better:</p>
<p><a id="fig14" href="https://img.incoherency.co.uk/2096"><img src="https://img.incoherency.co.uk/2101"></a><br>
<i>Fig. 14: Unaligned stack of 171 frames with tracking and auto-guiding (cf. <a href="#fig13">fig. 13</a>).</i></p>
<p>(But we'd still want to align them better than this for "real" stacking).
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/pikon-autoguiding.html</link>
   <guid>http://incoherency.co.uk/blog/stories/pikon-autoguiding.html</guid>
   <pubDate>Wed, 23 Jan 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Imaging the Orion nebula with the PiKon telescope</title>
   <description><![CDATA[On Friday night I took some photographs of the Orion nebula with my
motorised PiKon telescope from my back garden. There is lots of light pollution around, but this is the final image I got:]]></description>
   <content:encoded><![CDATA[<p>On Friday night I took some photographs of the <a href="https://en.wikipedia.org/wiki/Orion_Nebula">Orion nebula</a> with <a href="https://incoherency.co.uk/blog/stories/pikon-telescope-hardware.html">my
motorised PiKon telescope</a> from my back garden. There is lots of light pollution around, but this is the final image I got:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2066"><img src="https://img.incoherency.co.uk/2066/thumb"></a></p>
<p>It's not a very <i>good</i> image of the Orion nebula, but it is substantially better than I was able to get from a single
unprocessed exposure.</p>
<p>Disclaimers: I don't actually know anything about astrophotography. I don't know if I'm using the correct terminology. I
don't know if I'm using the correct technique. This is just what I managed to figure out from first principles and
a little research.</p>
<p>The Orion constellation looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2053"><img src="https://img.incoherency.co.uk/2053/thumb"></a></p>
<p>The Orion Nebula (<a href="https://en.wikipedia.org/wiki/List_of_Messier_objects">Messier object</a> 42, or "M42") 
is a nebula in the Orion constellation. The <a href="https://www.youtube.com/user/DeepSkyVideos">Deep Sky Videos</a>
YouTube channel has quite a good <a href="https://www.youtube.com/watch?v=KOXm7W8f6wo">video on M42</a>.
To the naked eye the nebula appears to be just one bright star in
<a href="https://en.wikipedia.org/wiki/Orion%27s_Sword">Orion's "sword"</a>.</p>
<p><h3>Limitations</h3></p>
<p>The image from my telescope is slightly wobbly while the motion tracking is operating, I believe this is because
it makes the tube vibrate. I therefore
only use the tracking to keep the telescope lined up with the object when preparing to take a photograph, and then turn it off
to actually take the photo. To get lots of photos of the same object I use the "timelapse" mode in the interface. This results
in some motion of the object from one frame to the next (because the Earth is spinning), which needs to be fixed later:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2054"><img src="https://img.incoherency.co.uk/2054/thumb"></a></p>
<p>(these are 1-second exposures 5 seconds apart).</p>
<p>This picture also demonstrates my continued difficulties in bringing my PiKon to a sharp focus: a correctly-focused
star should be a single point, whereas I have a blurry smudge.</p>
<p>The maximum exposure time that <a href="https://github.com/silvanmelchior/RPi_Cam_Web_Interface">RPi Cam Web Interface</a>
seems to support is 1 second. The Pi camera can do a bit more, but I haven't yet worked out how to get the web interface to
support it. It might require a custom compiled <a href="https://github.com/rpicopter/raspimjpeg">raspimjpeg</a>. And at
any rate, the stars are already starting to look streaky at 1 second of exposure. They'd be worse at longer exposures.</p>
<p>The JPEG files we get from the interface only give us 8 bits per channel of colour data. Getting RAW data with <tt>raspistill
--raw</tt> <a href="https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=44918">seems to include 10 bits per channel</a>,
so if that's easy to use, it might be worth working out how to get raspimjpeg to include the RAW data.</p>
<p>The Orion nebula is about 4x larger than the PiKon field-of-view, in both axes, so ideally you would take a photograph
with something that has less magnification than the PiKon. Fortunately (?) it's quite dim around the edges, so I wasn't
able to see any more than the centre of the nebula anyway, which fits comfortably within the PiKon field-of-view.</p>
<p><h3>Operating the telescope</h3></p>
<p>I point the telescope at the object I want to look at, using Stellarium, pause tracking using my <a href="https://github.com/jes/pikontroll">pikontroll</a>
GUI in RPI Cam Web Interface, and periodically resume and re-pause tracking whenever the object nears the edge of the view,
to re-centre it in the frame. An equatorial mount would be far superior.</p>
<p>A single 1-second exposure with ISO set to 800 looked like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2033"><img src="https://img.incoherency.co.uk/2033/thumb"></a></p>
<p>I tried various other combinations of ISO and exposure time, and this one produced the best results.</p>
<p>We could easily crop off (or disable) the timestamps before proceeding,
but I've left them in all of the pictures because they show some interesting effects.</p>
<p>We can whack the levels up ("Colours" menu => "Levels..." in the GIMP):</p>
<p><a class="img" href="https://img.incoherency.co.uk/2056"><img src="https://img.incoherency.co.uk/2056/thumb"></a></p>
<p>(I set the maximum brightness to be at 22 out of 255, which means all pixel values get scaled by a factor of ~11.6x).</p>
<p>At this level we can see some detail of the nebula, but there is a lot of background noise. We also only have 23 distinct
brightnesses so we've effectively only got 4.5 bits per channel. This would be substantially better if we'd started out
with 10-bit colour data instead of 8-bit, but the noise would still be there.</p>
<p>So to improve the image, we want to stack together lots of individual exposures, in an attempt to average out noise and amplify
signal.</p>
<p><h3>Exposure stacking</h3></p>
<p><h4>1. Alignment</h4></p>
<p>Before we can blend the exposures together, we need to align them.</p>
<p>To align 2 exposures, we can load them in separate layers in the GIMP, and set the top layer mode to "grain extract".
This mode shows us the differences between 2 layers. It's similar to the "difference" layer mode, except it centres around middle
grey instead of black so it's a bit easier to use.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2061"><img src="https://img.incoherency.co.uk/2061/thumb"></a></p>
<p>The timestamps here are overlapping (and therefore invisible), but the stars are not, because the photos were taken 5 seconds
apart with no tracking.
As we start to move the top layer to align the stars, the timestamps separate from each other and the stars get closer:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2062"><img src="https://img.incoherency.co.uk/2062/thumb"></a></p>
<p>And when we've got the layer properly aligned, the stars are almost invisible:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2063"><img src="https://img.incoherency.co.uk/2063/thumb"></a></p>
<p>To align a large number of exposures, open them all with the "Open as layers..." tool, set them all to invisible except the bottom
one, and then individually align each layer with the bottom layer using the "grain extract" layer mode. This takes an amount
of time linear in the number of layers, but you get faster with practice. You want to make sure all layers are aligned to
a single "master" layer, rather than aligning each one to the one immediately underneath it, to avoid accumulating errors.</p>
<p><h4>2. Blending</h4></p>
<p>With 2 layers correctly aligned, we can switch the top layer's mode from "grain extract" to "addition" to add the pixel values
together (left: 1 exposure, right: 2 exposures aligned and added together):</p>
<p><small>(if you're on mobile, you'll probably have to mentally replace left/right with top/bottom).</small></p>
<p><a class="img" href="https://img.incoherency.co.uk/2033"><img src="https://img.incoherency.co.uk/2033/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2064"><img src="https://img.incoherency.co.uk/2064/thumb"></a></p>
<p>You'll note that everything is now brighter, and there are now 2 timestamps shown.</p>
<p>When we have more than 2 layers, we can set all but the bottom layer mode to "addition" to add <i>all</i>
of our layers' pixel values together.
In my case, I had too many exposures for a simple
addition to work well (everything was too bright), so I added a solid black layer at the bottom, and set all of the exposure layer
opacities to 25%. 46 exposures multiplied by 25% opacity gives 11.5x the brightness of a single exposure, which
is comparable
to what we did earlier with the "Levels" tool (left), although we now get a much better image (right):</p>
<p><a class="img" href="https://img.incoherency.co.uk/2056"><img src="https://img.incoherency.co.uk/2056/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2065"><img src="https://img.incoherency.co.uk/2065/thumb"></a></p>
<p>You can see the streak of timestamps which corresponds to (the opposite of) the way the sky moved in the frame.</p>
<p>Since most of the exposures have been dragged towards the bottom-left to align them, we've lost part of those images.
We can get this back by
making the canvas large enough to contain the entirety of every exposure:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2032"><img src="https://img.incoherency.co.uk/2032/thumb"></a></p>
<p><h3>Dark frames</h3></p>
<p>This is the part where I'm not really sure about the terminology. I don't think what I've made is referred to as a
"dark frame" by actual astrophotographers. It could
just as easily be a "dark flat", "flat dark", "bias frame", or something else. I need to learn more about this.</p>
<p><h4>1. Capturing images</h4></p>
<p>To capture the dark frame, you just want to take a handful of pictures of dark sky, in roughly the same direction as
your subject, using the same camera settings, so that you
get roughly the same levels of sensor noise and light pollution. I just moved the telescope off to the side until I was
convinced I was looking at black space and then took a short timelapse.</p>
<p>I left the tracking on while taking these photos because I didn't want any stars to drift into the view, but this turned out
to be a mistake. The best thing to do is leave tracking off, and leave a timelapse running for a while. Later on, just throw away
any exposures that include stars and only use the "good" ones to make the dark frame. Even if you have some dim stars, they
shouldn't affect the final dark frame if tracking is off, because they'll be in a different position each time.</p>
<p><h4>2. Blending</h4></p>
<p>Much like exposure stacking, open the dark frames with "Open as layers" in the GIMP. These layers don't need any alignment because
they should all be completely black. (Delete any layers which are not completely black).</p>
<p>Set all but the bottom layer mode to "darken only". This will result in an output image that shows, at each pixel, the minimum
intensity that we observed when imaging completely black sky. This encodes information about both sensor noise and light pollution,
and we can use it later to remove sensor noise and light pollution from our individual exposures of the nebula. If you want
to remove noise more aggressively you could try using "lighten only" mode, but I found that this was too aggressive and removed
too much detail.</p>
<p>Here's the dark frame I ended up with (actual on the left, exaggerated on the right):</p>
<p><a class="img" href="https://img.incoherency.co.uk/2036"><img src="https://img.incoherency.co.uk/2036/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2038"><img src="https://img.incoherency.co.uk/2038/thumb"></a></p>
<p>Things to note include:</p>
<p><ul>
<li><span style="color:red">Red</span> arrows: there are some stars faintly visible! This is a mistake. If I knew there were stars in
the view I would have pointed the telescope somewhere else. And if I'd had motion tracking turned off, the "darken only" layer mode would have been able to scrub out the stars.</li>
<li><span style="color:blue">Blue</span> arrow: there is a bright spot at the edge. This is always present in the Pi camera, so we
do want to remove it from our actual photos. I believe
it is caused by some component on the PCB next to the sensor that heats up part of the sensor.</li>
<li><span style="color:green">Green</span> arrow: there is another, slightly dimmer, spot at the edge. I've not noticed this in the
past when playing with photos from the Pi camera so I'm not sure what it is. Most likely it's the same sort of thing as the blue
spot. Regardless, it seems to be present in the actual frames as well, so we want to remove it, which means we do want it in the dark frame.</li>
<li>The timestamp is mostly still present, although if you zoom in you'll see the "seconds" digits are partly removed. This means
we'll remove most of the timestamp text from the actual photos, where the characters are the same.</li>
</ul></p>
<p><h4>3. Subtracting dark frames from nebula exposures</h4></p>
<p>To subtract the dark frame from another exposure, we simply place the dark frame in the layer above it and set the
dark frame's layer mode to "subtract".</p>
<p>Here's an original exposure (left), compared to the same exposure with the dark frame subtracted out (right):</p>
<p><a class="img" href="https://img.incoherency.co.uk/2056"><img src="https://img.incoherency.co.uk/2056/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2055"><img src="https://img.incoherency.co.uk/2055/thumb"></a></p>
<p>Both have been exaggerated by the same amount using the "Levels" tool (with max. set to 22, so ~11.6x brighter).</p>
<p>The primary effect is reducing the visibility of light pollution (i.e., it makes the background darker). We've got rid of some
noise (the vertical streaks are less pronounced, at least),
but not as much as I had hoped. Side effects are that we've introduced some faint dark spots where there were stars in the dark frame, and we've
blacked-out most of the timestamp text.</p>
<p><h3>Exposure stacking with dark frames</h3></p>
<p>To subtract the dark frame from all of the individual stacked exposures (as opposed to just one), we can use the GIMP's "layer group" feature.
We want to make 1 layer group for each of the nebula exposures, and inside each layer group we want to have the nebula
exposure on the bottom layer, and the dark frame above it:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2069"><img src="https://img.incoherency.co.uk/2069/thumb"></a></p>
<p>The nebula exposures are all aligned to the bottom-most exposure, and the dark frames are all aligned to the corresponding
nebula exposure.</p>
<p>The nebula exposures are set to layer mode "normal", and 100% opacity. The dark frames are set to layer mode "subtract" and
100% opacity,
and the layer groups are set to layer mode "addition" and 25% opacity. At the very bottom of the whole stack there is a single
black frame at 100% opacity.</p>
<p>Setting all this up 46 times is quite laborious, and if I do much more of it I intend to make some GIMP scripts to automate parts
of
the process. Once all the layers are aligned correctly and in the correct mode and opacity, we're done.
We can compare
our result from exposure stacking alone (left) to our final result incorporating dark frame subtraction (right):</p>
<p><a class="img" href="https://img.incoherency.co.uk/2032"><img src="https://img.incoherency.co.uk/2032/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2035"><img src="https://img.incoherency.co.uk/2035/thumb"></a></p>
<p>For comparison, here is the first ever photograph of the Orion nebula, taken in 1880 by Henry Drape:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2067"><img src="https://img.incoherency.co.uk/2067/thumb"></a></p>
<p>And to see just how much extra detail is really there, here's an image of the Orion nebula taken by the Hubble space telescope over
the course of 105 orbits of the Earth (left), and the same image, but with my image aligned to match (right):</p>
<p><a class="img" href="https://img.incoherency.co.uk/2070"><img src="https://img.incoherency.co.uk/2070/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2071"><img src="https://img.incoherency.co.uk/2071/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/exposure-stacking.html</link>
   <guid>http://incoherency.co.uk/blog/stories/exposure-stacking.html</guid>
   <pubDate>Tue, 08 Jan 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Towards a Better Pythagorean Cup</title>
   <description><![CDATA[There was an article on Hacker News the other day by David Richeson entitled
Make Your Own Pythagorean Cup.
A Pythagorean cup is a cup with a built-in siphon. Supposedly invented by Pythagoras, the cup functions just
like an ordinary cup as long as it is only filled to a certain level. If anyone gets greedy and tries to take
too much wine, the level rises above the top of the siphon, which causes the siphon to self-start, and the
greedy person is punished by having the entire contents of the cup dumped into their lap.]]></description>
   <content:encoded><![CDATA[<p>There was an article on Hacker News the other day by David Richeson entitled
<a href="https://divisbyzero.com/2018/12/31/make-your-own-pythagorean-cup/">Make Your Own Pythagorean Cup</a>.
A Pythagorean cup is a cup with a built-in siphon. Supposedly invented by Pythagoras, the cup functions just
like an ordinary cup as long as it is only filled to a certain level. If anyone gets greedy and tries to take
too much wine, the level rises above the top of the siphon, which causes the siphon to self-start, and the
greedy person is punished by having the entire contents of the cup dumped into their lap.</p>
<p>The TL;DR is that I designed a Pythagorean cup that looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2006"><img src="https://img.incoherency.co.uk/2006/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2023"><img src="https://img.incoherency.co.uk/2023/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2025"><img src="https://img.incoherency.co.uk/2025/thumb"></a></p>
<p>There are <a href="#stls">STL download links</a> below.</p>
<p>Wikipedia has a good diagram showing how the <a href="https://en.wikipedia.org/wiki/Pythagorean_cup">Pythagorean cup</a> works:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2009"><img src="https://img.incoherency.co.uk/2009/thumb"></a></p>
<p>At the end of his article David included a sketch of an alternative design for a Pythagorean cup,
which hides the siphon in the handle instead of a large protrusion in the centre of the cup:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2008"><img src="https://img.incoherency.co.uk/2008/thumb"></a></p>
<p><h4>First attempt</h4></p>
<p>I thought this was a great idea, so I fired up FreeCAD and had a go at it myself.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2003"><img src="https://img.incoherency.co.uk/2003/thumb"></a></p>
<p>While this was printing, "mrfusion" in the Hacker News comments mentioned that he had made a Pythagorean cup before,
and was disappointed that it took a long time to drain. It apparently "wasn’t very impressive to wait 30 seconds while
the water trickled out. Just seems like a leaky cup".</p>
<p>Indeed, after my mug had finished printing:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2012"><img src="https://img.incoherency.co.uk/2012/thumb"></a></p>
<p>I too was disappointed to find that it took a long time to drain.</p>
<p><h4>Fluid mechanics</h4></p>
<p>I measured the drain rate by filling the mug with water to some level slightly above where the siphon starts, with
my finger over the end of the siphon, and then allowing the mug to drain into a measuring jug while I timed how
long it drained for. I stopped timing as soon as the flow became non-continuous (i.e. turned from a flow to a
drip) because the empty siphon tube continues dripping for quite some time after it has stopped flowing. I repeated
this measurement several times because I have a GCSE in science and I'm not afraid to use it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2014"><img src="https://img.incoherency.co.uk/2014/thumb"></a></p>
<p><i>(you can just about see the water trickling out of the bottom of the mug)</i></p>
<p>I found that the mug drained 200ml in 90 seconds, for an average of 2.2 ml/sec. Not very impressive. Just seems like a leaky cup.</p>
<p>I observed that the rate at which the water drains out is highest at the start, and slows down as the level drops.
This makes sense. When
the water level is higher, there is more pressure pushing water out. In fact, the
pressure on the water at the top is 0, and rises linearly as you move towards the bottom. This means that the pressure
pushing water out drops linearly as the level drops.
<a href="https://en.wikipedia.org/wiki/Pascal%27s_law">Pascal's law</a> tells us that "a pressure change at any point in a
confined incompressible fluid is transmitted throughout the fluid such that the same change occurs everywhere". This means
that, while the pressure inside an open container is linear in the height of water above it, the pressure at the exit of
a siphon is always equal to the pressure at the pickup of the siphon because the water inside the tube is a confined incompressible
fluid.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2017"><img src="https://img.incoherency.co.uk/2017/thumb"></a></p>
<p>The pressure at the bottom (i.e. at the pickup of the siphon) decreases as the depth of the water in the container decreases.
<a href="https://en.wikipedia.org/wiki/Bernoulli%27s_principle">Bernoulli's principle</a>
tells us that, all else remaining equal, flow rate is linear in pressure.
So when siphoning out of a container with uniform volume along its height (e.g. a perfect cylinder), we have something like:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2018"><img src="https://img.incoherency.co.uk/2018/thumb"></a></p>
<p>(I think it drops exponentially, and cuts off at the point where the level in the cup drops below the top of the
pickup of the siphon).</p>
<p>This informs our first design improvement: we want most of the cup's volume to be at the top, so that
we get to spend more time at a high flow rate, and we want less of the volume at the bottom, so that we spend less time
at a low flow rate.  
The area underneath this chart is the total volume of water drained from the cup (ml/sec * sec = ml). If we reduce the
amount of volume, for a given flow rate, we empty the cup faster. This means that in particular we want to reduce the
diameter at the bottom of the cup, rather than increase it at the top, otherwise the increased flow rate will be cancelled
out by increased volume.</p>
<p>mrfusion suggested using a larger siphon tube to increase the flow rate, but I was initially skeptical of this as
I thought a larger tube would reduce the strength of the effect (it's easier to suck water up a straw than up
a drainpipe). It turns out this isn't the case because you also get a larger quantity of water doing
the sucking. According to Bernoulli's principle, the velocity of the flow would remain unchanged. If the velocity
is the same, and the cross-sectional area is increased, then we flow more millilitres per second. So this is our
second design improvement: we definitely want to increase the diameter of the tube.</p>
<p><h4>Second attempt</h4></p>
<p>"tobr" suggested an alternative way to route the siphon tube which appears superior:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2019"><img src="https://img.incoherency.co.uk/2019/thumb"></a></p>
<p>By looping the tube around the handle, instead of up and down just one side of the handle, we can use the entire handle as
a tube and fit a larger tube inside it.</p>
<p>I got back in FreeCAD and modelled a new mug, using what I learnt about fluid mechanics and tobr's tube routing idea.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2005"><img src="https://img.incoherency.co.uk/2005/thumb"></a></p>
<p>Note that the internal diameter at the bottom of the mug is even smaller than it appears from the outside. This
serves the dual purposes of creating space for the tube inside the handle, and reducing the volume of water in the low-flow-rate
region of the mug.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2013"><img src="https://img.incoherency.co.uk/2013/thumb"></a></p>
<p>Testing the new mug in the sink, I was delighted to find that it drained much quicker than the first one. I repeated the
measurement with the stopwatch and measuring jug, and found that the new mug drained 150ml in 12 seconds, for an
average flow rate of 12.5 ml/sec. The average flow rate is 5.6x better and the time to drain is 7.5x better.</p>
<p>This picture shows a comparison of the tube sizes:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2020"><img src="https://img.incoherency.co.uk/2020/thumb"></a></p>
<p>The cross-sectional area of the tube is increased from about 12mm<sup>2</sup> to 56mm<sup>2</sup> (4.7x larger). This accounts
for most of the improvement in average flow rate, with the rest of the improvement coming from the reduction in volume at the
bottom of the mug.</p>
<p><h4>Minor improvements</h4></p>
<p>I'm pretty much happy with the performance of this mug, but I don't like how it looks. The handle looks rather contrived, not
nearly as elegant as the one in tobr's sketch, and I don't like the tesselation pattern on the surface:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2021"><img src="https://img.incoherency.co.uk/2021/thumb"></a></p>
<p>This is because FreeCAD has to convert my nice smooth model of a mug into a mesh of triangles in order to export it for 3d
printing. Fortunately, the quality is adjustable. I solved this by changing the "Maximum deviation depending on the model
bounding box"
in the "Part Design" => "Shape View" settings from 0.1% to 0.01%. This did increase the size of the exported STL file
by a corresponding factor of ~10 (from about 1.4MB to 12MB) but that's not a problem.</p>
<p>I also smoothed out the sharp edges on the handle.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2006"><img src="https://img.incoherency.co.uk/2006/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2023"><img src="https://img.incoherency.co.uk/2023/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/2025"><img src="https://img.incoherency.co.uk/2025/thumb"></a></p>
<p>Since this is only a cosmetic change, this mug still contains 150ml of water and empties in 12 seconds.</p>
<p><h4>Printing one</h4></p>
<p>It took me about 6h30 to print each one. Make sure to use plenty of solid layers/perimeters so that it's watertight. A cup
that isn't watertight isn't very useful, and a siphon that isn't airtight won't even work.
I looked at getting a higher-quality one of these made by ShapeWays but it was going to cost upwards of $80 even in plastic
so I gave it a miss. It would be cool to have
a ceramic one but although they do advertise 3d printed ceramics, I couldn't find the option for that in ShapeWays.
Possibly this model is too intricate for their ceramics process so they didn't list it as an option?</p>
<p><span id="stls">STL download links:</span><br>
<a href="https://incoherency.co.uk/interest/pythagoreancup.stl">First attempt</a> (630k)<br>
<a href="https://incoherency.co.uk/interest/pythagoreancup2.stl">Second attempt</a> (1.4M)<br>
<a href="https://incoherency.co.uk/interest/pythagoreancup2b.stl">Final version</a> (12M)<br></p>
<p>It is probably not advisable to use one long-term as it will be pretty impossible to clean the inside of the tube. Also it is
not advisable to serve hot drinks in any type of cup made from PLA.</p>
<p><h4>Mercury in a Pythagorean cup</h4></p>
<p>The <a href="https://www.youtube.com/channel/UCtESv1e7ntJaLJYKIO1FoYw">Periodic Videos</a> YouTube channel has a video
of <a href="https://www.youtube.com/watch?v=ISfIT3B4y6E">mercury in a Pythagorean cup</a>.
Towards the end they show that if some mercury is poured into the bottom of the cup, and then water is poured on top of
the mercury, it is safe to fill the cup all the way to the top. The reason for this is that the mercury is so much more dense
than the water that the weight of the water is not enough to push the mercury to the top of the siphon. It would work with
any 2 immiscible liquids of different densities, as long as you put enough of the heavier liquid in that the lighter liquid
can't push it to the top of the siphon.</p>
<p><a class="img" href="https://img.incoherency.co.uk/2026"><img src="https://img.incoherency.co.uk/2026/thumb"></a></p>
<p>(If you put the water in first, and then top it up with mercury, I think the mercury would sink to the bottom and would push
some water over the top of the siphon, but the weight of the water falling out of the siphon wouldn't be enough to pull the
mercury out, so either the water would fall out and get replaced with air, or the water would just stay suspended
part-way down the downtube of the siphon, depending on whether the tube is wide enough for the water's surface tension to hold
it together. I might be wrong.)</p>
<p><h4>Other people's Pythagorean cups</h4></p>
<p>I found a handful of other Pythagorean cup designs that are shaped like a mug.</p>
<p><a href="https://www.thingiverse.com/thing:1627448">This one from 2016</a> by paulo2345 is designed like the traditional Pythagorean
cup, with the protrusion in the centre, but is otherwise shaped like a mug with a handle:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2028"><img src="https://img.incoherency.co.uk/2028/thumb"></a></p>
<p><a href="https://www.thingiverse.com/thing:1627448">This one from 2016</a> by "KIT Trainee Group" hides the siphon in the walls of the mug instead of in the handle:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2027"><img src="https://img.incoherency.co.uk/2027/thumb"></a></p>
<p>And <a href="https://www.thingiverse.com/thing:228198">this one from 2014</a> by <a href="https://www.me.uk">Adrian Kennard</a>
(a very interesting chap, and also the man behind
<a href="https://aa.net.uk/">the world's greatest Internet Service Provider</a>) actually does route the siphon through the handle:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2029"><img src="https://img.incoherency.co.uk/2029/thumb"></a></p>
<p><h4>Future work</h4></p>
<p>It might be interesting to make a "Pythagorean sippy cup". It would flow twice as fast as you get twice as many handles through
which to route the siphon:</p>
<p><a class="img" href="https://img.incoherency.co.uk/2030"><img src="https://img.incoherency.co.uk/2030/thumb"></a></p>
<p>Given what we've learnt about fluid mechanics, a wine-glass-derived design is not a bad idea as its volume tapers
off quite sharply towards the bottom. I couldn't find a type of glass that both tapers to a point at the bottom and has
a handle, but if there is one then it would probably be a good candidate. It is not safe to hide the siphon in the walls
of a cup that does not have a handle, as there is a risk that even a non-greedy drinker might hold the cup with the siphon
facing towards himself. As he tilts the cup to drink from it, the siphon would fill up and self-start, and 
"I pour hot squash all over myself and we all have a good chuckle. Everyone except muggins here."</p>
<p>There is also scope to design a <a href="https://en.wikipedia.org/wiki/Puzzle_jug">puzzle jug</a> that incorporates a
siphon into its mechanism, either as the correct way to remove the liquid, or a trick to dump the liquid into
the puzzler's lap.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/pythagorean-cup.html</link>
   <guid>http://incoherency.co.uk/blog/stories/pythagorean-cup.html</guid>
   <pubDate>Fri, 04 Jan 2019 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>First Light in the PiKon telescope</title>
   <description><![CDATA[On Thursday night I had an opportunity to try out my motorised PiKon
telescope for the first time. Emma and I drove to a cemetery that is about 5 minutes away. It is not an ideal
astronomy spot, but it is better than our back garden as it is a bit further from trees, tall buildings, and street lights.]]></description>
   <content:encoded><![CDATA[<p>On Thursday night I had an opportunity to try out my <a href="https://incoherency.co.uk/blog/stories/pikon-telescope-hardware.html">motorised PiKon
telescope</a> for the first time. Emma and I drove to a cemetery that is about 5 minutes away. It is not an ideal
astronomy spot, but it is better than our back garden as it is a bit further from trees, tall buildings, and street lights.</p>
<p>The first step upon arrival is levelling the telescope with the adjustable feet. This is required so that the horizontal rotation
does not contribute to vertical rotation, and vice versa.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1986"><img src="https://img.incoherency.co.uk/1986/thumb"></a></p>
<p>I have glued a small circular spirit level indicator onto the base of the telescope to make this easier.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1987"><img src="https://img.incoherency.co.uk/1987/thumb"></a></p>
<p>With the telescope levelled, it's time to boot it up and get it talking to the laptop. I was disappointed by Ubuntu's
wifi management interface. I was hoping to be able to start either a wifi "hotspot", or an ad-hoc wifi network,
and get the laptop and the Raspberry Pi talking directly to each other. Unfortunately, this is too hard,
and the easiest way I found to do it was to setup a hotspot on my phone, and have both the laptop and the Pi connect
to the phone.</p>
<p><h4>Finding the moon</h4></p>
<p>We can then set the initial aim of the telescope by sighting along it from the base, and turning it until it
seems to be pointed at the moon. It could probably do with a spotting scope on the side, pointed in the same
direction but with much lower magnification.</p>
<p>Having pointed the telescope vaguely near the moon, we have to try to find the moon in the sky so that we have a known
direction to calibrate the motorised mount against. The telescope was not focused at this point, which makes looking
at stars impossible. However, this turned out to be helpful for finding the moon. Because the telescope was out of focus,
the light from the moon is spread out over a large area, which means we only need to find some of the light from the moon,
and then drop the exposure so that we see a gradient across the field of view. Finding the moon is then as simple as
repeatedly following
the gradient towards the light, and dropping the exposure as we get closer to the moon, until we reach it.</p>
<p>I didn't take any pictures of this process, so you'll just have to use your imagination.</p>
<p>Having found the moon, I manually dragged the focusing arm in and out to get it close to focused, so that the servo's range of 
movement can be used to fine tune it. This manual setup should only be required once, because the focal length of
the mirror never changes, and all objects in space are almost-infinitely far away, so we will only ever need to do fine adjustments.
Just in case the telescope ever gets dismantled, I have marked the location of the focusing arm so that it can be reinstalled in
the right place to avoid having to recalibrate it.</p>
<p>I was eventually delighted to find this picture on the screen:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1984"><img src="https://img.incoherency.co.uk/1984/thumb"></a></p>
<p>My homemade telescope is actually receiving light that has bounced off the moon, and magnifying and focusing it well
enough to make out the craters
on the surface, using little more than a Raspberry Pi and a mirror! What a world we live in.</p>
<p>Now that we're pointing at the moon, we can use the "Receive current coords from Stellarium" button in the UI to tell the
control software
where it is currently pointing (I have a <a href="https://github.com/jes/RPi_Cam_Web_Interface">fork of RPi Cam Web Interface</a>
that adds the PiKonTroll panel to the left of the camera view, shown in above pic). After that, Stellarium and the telescope are in sync, and a.)
the telescope should track the point in the sky that
it is looking at as the Earth rotates underneath it, and b.) the telescope should be able to aim at any object Stellarium
tells it to with no more manual calibration required.</p>
<p>I tried to focus it a bit better, but even with the gear reduction on the servo, it was extremely sensitive. Only
about the middle 10% of the servo range was actually useful.</p>
<p><h4>Photographing the moon</h4></p>
<p>The telescope wasn't quite tracking the moon properly, and at the time I couldn't work out why. The moon was slowly
"drifting" in the
frame. The motors were moving as if they were tracking the sky, but it wasn't quite synced up. I later realised that
the time on the Raspberry Pi was set wrong, which throws off all the calculations about where things are in the sky. I'll have
to remember to synchronise the clock in future.</p>
<p>We got this picture of the moon:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1981"><img src="https://img.incoherency.co.uk/1981/thumb"></a></p>
<p>As you can see, there is still room for improvement on the focusing, but it's a good start.</p>
<p>I like to think of this as the <a href="https://en.wikipedia.org/wiki/First_light_(astronomy)">First Light</a> image.</p>
<p><blockquote>The first light image is normally of little scientific interest and is of poor quality, since the various telescope elements are yet to be adjusted for optimum efficiency. Despite this, a first light is always a moment of great excitement, both for the people who design and build the telescope and for the astronomical community, who may have anticipated the moment for many years while the telescope was under construction.</blockquote></p>
<p>Mostly this is accurate, although I am not sure how excited the astronomical community is.</p>
<p>You may also notice some strange spots on the image:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1995"><img src="https://img.incoherency.co.uk/1995/thumb"></a></p>
<p>These are most likely caused by dust on the sensor, because the sensor is open to the air and I have not yet
got any sort of "lens cap" to keep things from going inside. I don't think the spots could be caused
by dust on the mirror (although there definitely is some dust on the mirror), because they are unaffected by focusing.
This is unfortunate as the sensor is very delicate and I am not confident that I can clean it without making it worse.
I'm going to leave it alone
for the time being, and eventually I might try rinsing it in isopropyl alcohol. In the worst case I break it and upgrade to
the newer Raspberry Pi camera which has a higher resolution anyway.</p>
<p><h4>Focusing improvements</h4></p>
<p><a class="img" href="https://img.incoherency.co.uk/1991"><img src="https://img.incoherency.co.uk/1991/thumb"></a></p>
<p>I have printed new gears for the servo which raise (or lower?) the
gear ratio from 4.5:1 (left) to 10.3:1 (right). More than twice as good! But still, only about 20% of the servo range will
be useful, and I can't really print a smaller gear than the one that is now on the servo. That gives us about 350 "steps" of
useful servo range, and with some UI improvements to make them easier to access precisely (instead of just blindly
dragging a slider with no numeric feedback), it will at least be better than it was.</p>
<p>A <a href="https://en.wikipedia.org/wiki/Bahtinov_mask">Bahtinov mask</a> can be used to focus on smaller objects. This is
a partially-opaque filter to be placed in front of the "objective" of the telescope, to deliberately create diffraction
spikes at certain angles. Correct focus is achieved when the "straight" diffraction spike runs directly through the centre
of the two angled spikes, at which point the mask can be removed. GIF from Wikipedia:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1994"><img src="https://img.incoherency.co.uk/1994/thumb"></a></p>
<p>I have designed one suitable for fitting over the end of a PiKon telescope (in particular, the PiKon needs the Bahtinov mask
to have a hole in the middle for the focusing arm to stick through):</p>
<p><a class="img" href="https://img.incoherency.co.uk/1993"><img src="https://img.incoherency.co.uk/1993/thumb"></a></p>
<p>I have not yet tested it so it is possible that it doesn't work, but I expect it does work. You can
<a href="https://incoherency.co.uk/interest/pikon-bahtinov-mask.stl">download the STL file</a> if you want to print one.</p>
<p><h4>Moving on</h4></p>
<p>Just as we were about to try to take some pictures of Mars from the cemetery, a car pulled up next to us. It was a man from the council telling
us that we need to leave
as the cemetery is about to be closed. What a fascist, I had no idea it got closed at night time. What are our council taxes
paying for if we can't even use the facilities? Anyway, we packed up and left.</p>
<p>The next place that I had in mind for astronomy is "Tog Hill picnic area". It is a small car park just off the A420.
When we arrived we were surprised to find that there were a lot of other cars in the car park. Who goes for a picnic in the dark?
A chap parked his car next to us as Emma was levelling the telescope and asked her if it was a heater, but we didn't think
anything of it and started trying to find the moon again.</p>
<p>Eventually a man parked his van in front of the telescope so we had to move it once more. As I was moving the telescope
he remarked to me "you know what this is don't you? it's a dogging site" in a thick Welsh accent. I suppose that
explains why there are so many cars there, and why some of them have the interior lights on. This, combined with the constant
commotion of people coming and going, and the surprising number of street lights that were around, meant that we couldn't really
get comfortable and we quickly left.</p>
<p>It is apparently "the UK's premier dogging site". Who knew?</p>
<p><a class="img" href="https://img.incoherency.co.uk/1985"><img src="https://img.incoherency.co.uk/1985/thumb"></a></p>
<p>So we won't be going back to Tog Hill picnic area. Not with the telescope, at least.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/pikon-telescope-first-light.html</link>
   <guid>http://incoherency.co.uk/blog/stories/pikon-telescope-first-light.html</guid>
   <pubDate>Sun, 16 Dec 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Flat Earth and the Coriolis Force</title>
   <description><![CDATA[I've been learning about "flat-Earthers" recently. They're a fascinating group of people who genuinely believe
that the Earth is flat and that governments, scientists, and industry are in on a big conspiracy to trick
everyone into thinking the Earth is round.]]></description>
   <content:encoded><![CDATA[<p>I've been learning about "flat-Earthers" recently. They're a fascinating group of people who genuinely believe
that the Earth is flat and that governments, scientists, and industry are in on a big conspiracy to trick
everyone into thinking the Earth is round.</p>
<p><h3>Flat Earth</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/1976"><img src="https://img.incoherency.co.uk/1976/thumb"></a></p>
<p>Mostly the flat Earth arguments are derived from a fundamental misunderstanding
of gravity, leading to statements like "any body of water always sits level, so how can the seas curve around the Earth?" and
"a railway from east to west coast of the UK would have to rise so far up in the middle that no train would
be able to make the climb". There is also extrapolation of an "8 inches of curvature per mile squared" surveying rule-of-thumb well
beyond its useful range, references to passages from religious texts, and observations that
photos of things taken in space look funny. There is a widespread belief (among the flat Earth community) that
all space travel is fake. It really is fascinating to look into. But make sure you go in with either a good grasp of
how gravity works, or a healthy dose
of <a href="https://web.archive.org/web/20180406150429/https://squid314.livejournal.com/350090.html">epistemic learned
helplessness</a>, else you might turn into One Of Them.</p>
<p>(Incidentally, "epistemic learned helplessness" is a really interesting concept, I recommend reading the essay. It's about the
idea that most people are better off just going with whatever is most popular, rather than listening to
reason, because they lack the skills to correctly evaluate ideas, and are more likely to be misled by bad ideas than to
be misled by copying the popular idea).</p>
<p>A lot of the YouTube comments on flat-Earth videos are from round-Earthers trying to show that
the video is wrong. Obviously the video is wrong, but what I find really interesting is that many of the
round-Earthers are wrong about why the video is wrong! Ideas like "the laser is visible on the other side
of the lake because the laser is bent down by gravity", or "the reason a hammer and a feather accelerate downwards at the same
rate is because their masses are quite close to each other relative to the Earth". Flawed debunking of the flat-Earth concepts
probably contributes to why the flat-Earthers continue to believe their concepts: they keep seeing wrong
arguments for why the Earth is round, so the Earth must not be round. (Although, even if the arguments were right,
"one can't be reasoned out of a position that one wasn't reasoned into").</p>
<p><h3>Foucault's Pendulum</h3></p>
<p>An interesting experiment that shows that the Earth is rotating is <a href="https://en.wikipedia.org/wiki/Foucault_pendulum">Foucault's Pendulum</a>. This is just a large pendulum whose motion can be observed.
The weight on the pendulum has inertia, and the pendulum is mounted on a rotating body (the Earth).
The pendulum "wants" to keep swinging in the same direction,
but our reference points (buildings, trees, etc.) for that direction are all fixed to the Earth, and therefore our
reference points are rotating relative to the pendulum. If we assume the reference points are not rotating, it appears
as though the motion of the pendulum is rotating.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1977"><img src="https://img.incoherency.co.uk/1977/thumb"></a></p>
<p>Foucault's Pendulum is also consistent with the Earth being round, because the magnitude of the effect decreases as you move from the
North pole to the equator (at which there is no effect, because at the equator the pendulum is perpendicular to the
Earth's rotation axis), and then reverses, and increases in magnitude as you move from the equator to the South pole.</p>
<p><h3>Coriolis Force</h3></p>
<p>The rotation of the oscillation of Foucault's Pendulum is described by the
<a href="https://en.wikipedia.org/wiki/Coriolis_force">Coriolis Force</a>. The Coriolis force is not a "real" force (in the
same way that the centrifugal force is not a "real" force), it is just a force that appears to exist when an object
is measured from within a rotating reference frame. When turning left in a car, you feel yourself being pushed right, towards
the outside of the turn, by the "centrifugal force". You're not <i>actually</i> being pushed towards the outside of the turn,
you're just an object
moving in a straight line (<a href="https://en.wikipedia.org/wiki/Newton%27s_laws_of_motion">Newton's first law</a>)
while the car moves left.</p>
<p>Similarly, the Coriolis force is not actually rotating Foucault's pendulum. The mass on the end of the pendulum is just
an object moving in a straight line (ish) while the Earth rotates underneath it. Once this is understood, the Coriolis
force needs no explanation at all. It is a natural consequence of Newton's laws of motion on an object that
is observed from a rotating reference frame. This might seem obvious to you, but I didn't get it until I'd thought about it
for a little while.</p>
<p><h3>Throwing a ball on a spinning disc</h3></p>
<p>While thinking about the Coriolis force it occurred to me that if you were sitting on a spinning disc, and you threw a ball
straight towards the centre of the disc, you might be able to catch it again on the other side if the disc is spinning fast
enough. I looked for some examples
of people actually doing this, and couldn't find any. I did find a couple of videos that <a href="https://www.youtube.com/watch?v=mPsLanVS1Q8">demonstrated</a>
the <a href="https://www.youtube.com/watch?v=dt_XJp77-mk">effect</a>, but failed to make
the connection that the ball could be returned to the thrower.
In addition, they both made
the same mistake. The people on the spinning disc made no effort to cancel out their own velocity from the initial velocity
of the ball. They throw the ball directly forwards from where they're sitting, but since they are moving
around the disc, they already have some velocity tangent to the disc. A ball that was truly thrown in a straight line
across the centre of the disc would pass over the centre point of the disc, but the balls in those videos do not.</p>
<p>I did find <a href="https://www.youtube.com/watch?v=_36MiCUS1ro">one example</a> in which the ball is returned to the thrower.
At about 0:14, the red person sits on the disc and rolls a ball out to the side, cancelling out the tangential velocity, and 
waits for the ball to curve around and come back. Unfortunately, since the ball was rolled across the disc instead of thrown through the air,
this too has a mistake. Consider a ball which is placed stationary on the disc: the centrifugal force would cause it to move
towards the outside, with no Coriolis force required at all!</p>
<p><h3>Javascript simulation</h3></p>
<p>Since YouTube University wasn't delivering the goods, I made my own demonstration in Javascript. You can
<a href="https://incoherency.co.uk/coriolis/">play with it here</a>:</p>
<p><a href="https://incoherency.co.uk/coriolis/"><img src="https://img.incoherency.co.uk/1978"></a></p>
<p>We have two views of the same scene. The left view is fixed in space, and the right view rotates with the disc so that the disc
appears to be still. There are 4 coloured dots on a spinning disc, and a ball can be thrown from the
red dot. The brown dots around the outside are fixed in space as reference points. On the view that is rotating with the
disc (in which the disc appears to be still and the brown dots appear to be moving), the
thrown ball appears to travel through a curved path even though no force is acting on it. This "phantom" force is the
Coriolis force. I did not actually implement any calculations for the Coriolis force. I simply simulated the movement in
an inertial reference frame, and the Coriolis effect appears naturally when the scene is observed from a rotating
reference frame.</p>
<p>If the tangential velocity is cancelled out (e.g. by setting V<sub>x</sub> to -0.64 m/s, at 10 rpm in the simulation), then the ball travels directly
through the centre of the disc. To an observer who is rotating with the disc, the ball appears to have been thrown off to one
side, before swinging around and passing through the centre.</p>
<p>Having spent some time playing with this, I remembered the timeless "Tanks" game:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1974"><img src="https://img.incoherency.co.uk/1974/thumb"></a></p>
<p>Each player has a tank on a hillside, and has to try to shoot a bullet at the other players' tanks, by adjusting the
gun angle and firepower. Gravity acts on the projectile so that it travels in a parabola.</p>
<p>Wouldn't it be fun to play a similar game, except instead of a hillside with gravity, the tanks are
positioned around the edge of a spinning disc? You can <a href="https://incoherency.co.uk/coriolis-tanks/">play with that</a>
as well. It starts out slow, so the Coriolis effect is small, and speeds up with each level.</p>
<p><a href="https://incoherency.co.uk/coriolis-tanks"><img src="https://img.incoherency.co.uk/1975"></a></p>
<p>The radial lines around the edge of the disc actually provide collision detection. Originally they did not, and the
winning strategy was to simply point your gun opposite to the direction of rotation, and then adjust the firepower so
that the tangential velocity is cancelled out. This causes the bullet to remain fixed in space, and then you just
wait for the disc to rotate around until your opponent crashes into your bullet.</p>
<p>Anyway, as it turns out: no, it's not very fun.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/coriolis.html</link>
   <guid>http://incoherency.co.uk/blog/stories/coriolis.html</guid>
   <pubDate>Sun, 09 Dec 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>My PiKon telescope hardware</title>
   <description><![CDATA[Since the last post I've been working on the hardware of my telescope.
I think the hardware is basically done, I just have a bit more software to write, and then need to wait for a convenient and
cloud-free night in which to try it out.]]></description>
   <content:encoded><![CDATA[<p>Since <a href="https://incoherency.co.uk/blog/stories/pikon-telescope.html">the last post</a> I've been working on the hardware of my telescope.
I think the hardware is basically done, I just have a bit more software to write, and then need to wait for a convenient and
cloud-free night in which to try it out.</p>
<p><h3>Parts</h3></p>
<p><a class="img" href="https://img.incoherency.co.uk/1959"><img src="https://img.incoherency.co.uk/1959/thumb"></a></p>
<p>The tube has a 3d printed clamp near the centre of mass, with a bearing pressed into each side. It also has 120 degrees of a
gear screwed to the side, for controlling the up-down angle ("altitude") of the telescope. At the top end I have fitted a large
gear on the threaded rod that controls the focus, and a servo with a small gear that drives the large gear. The servo
is able to turn through only 180 degrees, so most of the teeth on these gears are superfluous, but it gives plenty of
range to manually adjust the focus without worrying about the gear alignment. Having got the focus in the right
range manually, it can be fine-tuned using the servo. The focus is extremely sensitive, and I've found that the
range afforded by the servo is about 10x more than is required.</p>
<p>You might think that the altitude motor could drive past the end of the gear, causing the tube to flip over uncontrolled or
crash into the ground.
This does not happen, because the centre of mass of the tube lies on the same side of the tube as the gear. This means
if you drive off <i>either</i> end, the weight of the tube pulls the gear back towards the motor instead of flipping it over.
This is both a blessing and a curse, as we'll see later.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1960"><img src="https://img.incoherency.co.uk/1960/thumb"></a></p>
<p>The base of the stand is a small circle of MDF. I cut this circle on the table saw using
<a href="https://www.youtube.com/watch?v=xST3QUCjFBA">a technique I found on YouTube</a>. I made a sled for the saw,
and loosely screwed a piece of MDF to the sled. This allows us to take cuts that are a constant distance from the centre
point of the MDF. By rotating the MDF around the screw slightly with each cut, we can cut off finer and finer pieces of corner, until what
remains
is indistinguishable from a circle. A great benefit of this technique (in this application, at least) is that we are left
with a hole precisely in the centre, which can be used to align the hole for the pivot bolt. I cut a step into the circle using the same technique, with the blade lowered, and I 3d
printed a ring gear to sit in the step. This gear will remain stationary relative to the ground, and the telescope will rotate
by driving a gear around the outside of it. The gear is about as large as I can print in a single piece on my 3d printer.</p>
<p>I also pressed 3 nyloc nuts into the MDF, into which are threaded 3 bolts. These act as adjustable feet so that the telescope
can be accurately levelled (without accurate levelling, the "altitude" axis would also contribute a bit of "azimuth" movement,
and vice versa). I also 3d printed some finger-holds/rounded-feet and pressed them onto the heads of the bolts.</p>
<p>The teeth on these gears are only about 4mm tall. That means that if the centre point of the large gear is off the centre of
rotation by
only 2mm, it is impossible for it to mesh against the motor through a full 360 degree rotation. It would have been much easier
(i.e. unnecessary) to centre the gear accurately if the entire base plate was 3d printed in one piece. I didn't want to do this
as it would use up a lot of plastic,
and it would be less rigid than a piece of MDF. A good compromise might be to add a bit of plastic in the centre of the gear
that would
locate around the bolt that serves as the pivot point (so that it would be impossible to install the gear off-centre) but still
screw the entire thing to a piece of MDF for rigidity.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1961"><img src="https://img.incoherency.co.uk/1961/thumb"></a></p>
<p>A bolt is installed through the centre of the base. This is the axis around which the top part of the stand rotates.
I copied <a href="http://pikon.patrickaalto.com/pikonblog.html">Patrick Aalto's</a> idea of using 3 bearings in 3d printed
holders as wheels to support the weight of the upper part.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1962"><img src="https://img.incoherency.co.uk/1962/thumb"></a></p>
<p>The upper part of the stand is made of plywood, glued and screwed together with wooden battens. There is a stepped hole in the
middle with a bearing pressed into it to act as the rotation axis.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1963"><img src="https://img.incoherency.co.uk/1963/thumb"></a></p>
<p>The motor for the left-right rotation ("azimuth") is held in a 3d printed clamp which is screwed to the side of the stand. Since the
output shaft axis is offset slightly, the mesh of the gears can be adjusted by rotating the motor inside its clamp. And
since the motor is roughly the same diameter all the way along, the alignment of the gears can be adjusted by sliding
the motor up and down inside the clamp. I found the clamp to be a very elegant method of holding the motor.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1964"><img src="https://img.incoherency.co.uk/1964/thumb"></a></p>
<p>There's another identical clamp screwed to one of the uprights, for holding the altitude motor. The two holes at the
top are to allow a screwdriver to be inserted to reach the screws that hold it in place.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1965"><img src="https://img.incoherency.co.uk/1965/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/1966"><img src="https://img.incoherency.co.uk/1966/thumb"></a></p>
<p>At the top of the stand we have a bolt in each side. These locate in the bearings in the clamp around the tube and are
what hold the tube in place. From the first picture, the bolt on the right hand side is already in place. The tube is then lowered in
and slid over the right hand bolt, after which the left hand bolt can be slid into its bearing, and then the nuts tightened
around the plywood to hold everything in place:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1968"><img src="https://img.incoherency.co.uk/1968/thumb"></a></p>
<p>To connect the motor wires to the rest of the electronics, I soldered up a piece of protoboard to connect a ribbon cable
to a 2-row right-angle pin header.
Each motor has 6 wires (motor +, motor -, hall sensor 5v, hall sensor ground, hall signal A, hall signal B).
I initially thought that the "Motor -" wires could both be connected to
ground, but the L298N motor driver drives the motor in the reverse direction by applying positive voltage to the "Motor -"
wire and ground to "Motor +",
so they have to be unique to each motor. The hall sensor 5v and ground can be shared, however. So our 6 motor wires become
"only" 10 wires on the ribbon cable. The wires in the ribbon cable are very thin, including the ones that supply power
to the motors, but since the motors don't run for very long and aren't under much load, I think it'll be fine.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1969"><img src="https://img.incoherency.co.uk/1969/thumb"></a></p>
<p>Finally we have the electronics mounted on the side of the telescope. The red circuit board at the bottom is the L298N motor
driver. At the top is the Arduino Uno, and there are also some chocolate block connectors for power distribution.</p>
<p>At the time I took these pictures I had only received one of the motors. The "altitude" motor is installed like so:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1952"><img src="https://img.incoherency.co.uk/1952/thumb"></a></p>
<p>I don't like how it overhangs on the side, and it is designed so that it can be installed "inboard" and still leave the tube
a full 90 degrees of altitude control without crashing into the motor, but it was more convenient to screw it to the piece of
wood that was already there than to make a little wooden bracket to hold it. Maybe I'll move it in one day. Probably not.</p>
<p>I modelled all of the 3d printed parts except the gears in <a href="https://www.freecadweb.org/">FreeCAD</a>,
and I made the gears using a gear generator library in <a href="http://www.openscad.org/">OpenSCAD</a>.</p>
<p><h3>Problems (and some solutions)</h3></p>
<p><h4>Step resolution</h4></p>
<p>I wrote last time that the encoders on the motors gave 4096 steps per rotation of the output shaft, which should give us 0.08
degree increments in positioning if not geared down. Since learning how to read a quadrature encoder properly, I have learnt that
there are actually 4x as many steps available, so after the 19:1 gear reduction, we can measure 0.02 / 19 = 0.001 degree
increments. That's pretty good! The PiKon has a field-of-view of about 0.25 degrees, so we get 1/250 of the field-of-view
per step.</p>
<p>Unfortunately it is almost impossible to actually turn the motors to an exact step count. 1 step is about 1/16 of a turn of
the actual motor (i.e. the motor itself, before its little gearbox). I found that if you want the motor to turn for 10
steps, you need to switch it on for about 6 milliseconds, which means each step is 600 microseconds. But trying to
do exactly 1 step sometimes results in no steps at all, and sometimes results in 2 or 3, simply based on how close the shaft
is to the different low spots in the internal magnetic field, I guess? I eventually gave up on trying to hit exact step
counts and just let it tolerate anything within 4 steps of the target, which brings us back up to what I thought the
resolution was in the first place, so we can target about 1/60 of the field-of-view.</p>
<p>Using actual stepper motors would be the correct thing to do, instead of trying to make DC motors approximate steppers. If I were
to do it again I would use stepper motors.</p>
<p><h4>Wobbly image</h4></p>
<p>I've tested the telescope so far by pointing it at far-away objects out my window, and I have found that the
image gets quite wobbly while the motors are tracking objects in the sky. I am not completely sure why, but I think it is
a combination of comparatively-high acceleration when the DC motors switch on and off, a lack of rigidity in the tube, and
the <a href="https://en.wikipedia.org/wiki/Rolling_shutter">rolling shutter</a> of the camera.</p>
<p>Using stepper motors with smooth stepping (or ramping the current to DC motors up/down more gradually) would solve the
acceleration problem, which would mean lack of rigidity wouldn't matter, but there is no way to get rid of the rolling shutter without
replacing the camera (and therefore also the Raspberry Pi) with something considerably more expensive.</p>
<p><h4>Object tracking</h4></p>
<p>Being able to target 1/60 of the field-of-view would be fine if we just needed to aim at static objects. But the Earth is
rotating, and when your field-of-view is only 0.25 degrees, objects near the horizon can move entirely from one side
of the frame to
the other in only about 2 minutes, which means targeting 1/60 of the field-of-view means the object moves from one
"step" to the next in 2 seconds. The camera has a resolution of 2592 pixels across, so 1/60 is 43 pixels.
That means any kind of long exposure will have quite a blurred image. Even a 0.5 second exposure could have 10 pixels of
motion blur.</p>
<p>My "solution" to this, combined with the wobbliness of the image while moving, is to forget about trying to do mega-long
exposures and rely on exposure stacking instead. We could aim the telescope so that the object is at the top left of the frame,
pause the tracking to keep the telescope still,
and take many short exposures until the object leaves the bottom right of the frame, and then re-aim so that the object is
at the top left once more. Having collected a large number of short exposures, we can (manually) align them as pixel-perfectly
as possible, and add the images together. In this way we could approximate a single, accurately-tracked, long exposure.
It remains to be seen how well this will work.</p>
<p>A better solution would be to have finer control of the step count, and to fix the wobbling.</p>
<p><h4>Backlash</h4></p>
<p>Backlash is where a drive system has a "dead zone" when switching direction.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1970"><img src="https://img.incoherency.co.uk/1970/thumb"></a></p>
<p>In the diagram, the lower gear is rotating anti-clockwise to drive the upper gear. If the lower gear were
to stop and change direction, its first small movement would be taking up the backlash rather than driving
the upper gear in the reverse direction. This is pretty unavoidable. If the backlash were completely eliminated,
the gears would bind against each other instead of moving freely.</p>
<p>What this means is that when you move the motor 20 steps forwards and then 10 steps backwards, the output gear
is not at exactly the same point as it would be if you drove it 10 steps forwards. The more backlash, the further
away it will be. The easiest way to deal with this is to ensure that you always reach your step count from the
same direction. If you are at position 20 and you need to reach position 10, just drive all the way back to position
5 and approach 10 from below, and you'll be at the right place. That's fine when you can get away with it, but is not
really suitable for tracking objects with the telescope, because you won't track the object very well if you keep
having to drive past it, then drive forwards every time it moves 1/60 of the field-of-view.</p>
<p>Backlash can be compensated numerically. If you know there are always about 3 steps of backlash, then you can make sure
to move the motor 3 steps past the desired step count when turning in the reverse direction, and the problem is pretty much gone.
This would work for the azimuth (left-right) gear.</p>
<p>(If you're interested in this sort of thing, you might enjoy This Old Tony's
<a href="https://www.youtube.com/watch?v=K0XfRPi_h2M">Build Your Own CNC</a> series on YouTube, in which he covers using
commercial software and electronics to build a CNC "Etch-a-Sketch".)</p>
<p>But this brings us back to the altitude (up-down) gear. Since the weight of the telescope is always pulling it towards the centre of
the gear, the backlash direction actually inverts as you move it past the 45 degree point! That is more complicated to
compensate in software, and it probably means there is a small range of positions that is quite difficult to reach
because the telescope gear will essentially be "floating" in the space between the teeth on the motor gear. I'm planning
to ignore this.</p>
<p>My GUI will have to have some buttons to calibrate the precise position of the telescope, since it has no sensors
which would give it an absolute concept of which direction it is pointing. I plan to use this GUI to manually fine tune
the aim when pointing at a new object, and then the backlash only needs to get taken up during the calibration, and
then the object will be tracked accurately (modulo passing the midpoint of the altitude axis).</p>
<p><h4>Power supply</h4></p>
<p>I was initially planning to supply all of the power through the Raspberry Pi. I'd have a long USB cable powering the Pi,
the Arduino would be powered via its USB connection to the Pi, and the motors would be powered via the Arduino. Unfortunately
the current spikes when the motors start and stop are too much. They caused the voltage to drop for a split second, and the
Pi kept resetting itself.  </p>
<p>I've now settled on adding a second power supply via the barrel jack on the Arduino. It is safe for the Arduino to be
powered <a href="https://arduino.stackexchange.com/a/896">simultaneously through the USB port and the barrel jack</a>,
because it has an opamp to make sure the Arduino is powered by at least one input, while isolating the two power sources
from each other.</p>
<p>This means the motors are powered through the barrel jack, and the Pi is powered through its USB port, and the Pi does not
suffer voltage drops when the motors come on or off. It does mean that the telescope must be powered with 2 cables, but
that's fine. I have twisted together a 3 metre USB cable and a 3 metre car-socket-to-barrel-jack cable, so that I can
power both cables from within a car when "on location".</p>
<p><h4>Cabling</h4></p>
<p>Most of the cables on the telescope are confined to the upper section of the stand, and therefore they all remain in the
same place, relative to each other, as the telescope moves. The cables that need to go to the end of the tube are bundled
up in some cable wrap, and routed very close to the centre of rotation of the tube, so that the length remains constant
and the cables never have to stretch.</p>
<p>The power supply cables, however, are in danger of getting wrapped around the telescope, or tangled up in the gears,
if the telescope rotates around and around itself. I plan to ignore this problem for the time being. Hopefully I won't
do enough full rotations in any one sitting for it to become a problem, and if I do, hopefully I'll notice something
is wrong and fix it before it causes any damage.</p>
<p>A fun solution to this would be to mount a large-ish Lithium battery on the telescope itself, so that all of the cabling
is contained within the stand and nothing can get wrapped around it. But charging batteries is annoying so I'd rather not
have to bother.</p>
<p><h3>Software</h3></p>
<p>I've written a lot of the software, but not all of it. It's in
<a href="https://github.com/jes/pikontroll">https://github.com/jes/pikontroll</a> (but the repo is a mess). Currently there is
a program for the
Arduino that receives instructions over the serial port and controls the motors and focus servo accordingly. There
is a program for the Raspberry Pi that receives equatorial coordinates over the network from
<a href="http://stellarium.org/">Stellarium</a> based on <a href="http://yoestuve.es/blog/communications-between-python-and-stellarium-stellarium-telescope-protocol/">this example code</a>, converts them to altazimuth coordinates using mostly
<a href="http://pikon.patrickaalto.com/pikonblog.html">Patrick's code</a>, and then sends instructions to the Arduino over the
serial port. This program can also receive instructions to adjust the calibration of the motors and set the servo position.</p>
<p>Patrick lamented that Stellarium only sends the equatorial coordinates once every time you tell it to, which means
the telescope points at the point you tell it to, but then doesn't keep tracking it. But given that most
celestial objects don't move very much relative to the background, and the conversion from equatorial coordinates to
altazimuth coordinates only depends on the current time, it is quite easy to recompute the altazimuth coordinates periodically
and keep the telescope tracking the last coordinates that Stellarium sent to it. This unfortunately won't work for
tracking satellites, but it's good enough for planets, the moon, stars, etc.</p>
<p>There are still lots of bugs in my software, and I still need to write some sort of GUI, either integrated into
<a href="https://github.com/silvanmelchior/RPi_Cam_Web_Interface">RPi Cam Web Interface</a>, or a separate web page that I'd open
in a separate tab.</p>
<p>I was surprised with how much software has been required. As with most software, most of it is just "plumbing", i.e.
connecting together different parts that need to interoperate on the same underlying reality.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/pikon-telescope-hardware.html</link>
   <guid>http://incoherency.co.uk/blog/stories/pikon-telescope-hardware.html</guid>
   <pubDate>Mon, 03 Dec 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Ramblings About a Computerised Telescope</title>
   <description><![CDATA[The PiKon telescope is a brilliant design for a cheap but powerful telescope
using 3d printed parts and a Raspberry Pi. It is a Newtonian
reflector telescope, designed to be mounted and aimed with an ordinary camera tripod,
and then the Raspberry Pi camera is used to capture images. It uses a relatively inexpensive concave "spherical" mirror
for the primary mirror, and has no secondary mirror: the Pi camera is small enough that it is simply mounted in
the centre of the tube and captures light where the secondary mirror would normally be placed.]]></description>
   <content:encoded><![CDATA[<p>The <a href="https://pikonic.com/">PiKon telescope</a> is a brilliant design for a cheap but powerful telescope
using 3d printed parts and a Raspberry Pi. It is a <a href="https://en.wikipedia.org/wiki/Newtonian_telescope">Newtonian
reflector telescope</a>, designed to be mounted and aimed with an ordinary camera tripod,
and then the Raspberry Pi camera is used to capture images. It uses a relatively inexpensive concave "spherical" mirror
for the primary mirror, and has no secondary mirror: the Pi camera is small enough that it is simply mounted in
the centre of the tube and captures light where the secondary mirror would normally be placed.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1950"><img src="https://img.incoherency.co.uk/1950/thumb"></a></p>
<p>The PiKon was designed by a chap named Mark Wrigley, and there's an excellent
<a href="https://www.youtube.com/watch?v=nGrCyOcORvU">talk on his YouTube channel</a>, in which his enthusiasm for the
project is clear, explaining the idea and the motivations.</p>
<p>So obviously I want to build one of these, and I want to improve on it. The field-of-view of the telescope is about 0.25 degrees.
Due to the rotation of the Earth, this means objects far away from the North star "move" in the frame quite fast, which means
you need to constantly realign the telescope. I intend to build a robotic base that will automatically track
a given point in the sky. <a href="http://pikon.patrickaalto.com/pikonblog.html">Patrick Aalto</a> has a fascinating blog in
which he documents a similar project.</p>
<p>What I haven't seen anyone do with a PiKon telescope is imaging deep space
objects like galaxies and nebulae. I don't actually know if this will even work. It's possible that the Pi camera is
too noisy to collect enough light to make them out no matter how long your exposure is, but I want to try. Since these objects
aren't visible to the naked eye, having the telescope aimed by a computer is essential. Patrick used
<a href="http://stellarium.org/">Stellarium</a> to aim his telescope. Stellarium is a program which gives you a zoomable
view of the night sky,
as it would actually look from your location, and can send co-ordinates to telescope control software to make the
telescope point at any location you choose. I intend to use this.</p>
<p>It would be cool to build an <a href="https://en.wikipedia.org/wiki/Equatorial_mount">equatorial mount</a>. This is a type
of mount in which one of the axes is permanently aimed towards the North star, and thus tracking any object in the sky is
as simple as rotating around this axis at the same speed, and in the opposite direction, as the Earth's rotation. Much simpler
is an <a href="https://en.wikipedia.org/wiki/Altazimuth_mount">altazimuth mount</a>, which just rotates in 2 perpendicular axes,
so I'm going to start with that. I've bought some Chinese DC motors with builtin gearbox and encoder. The output shaft rotates
at 6rpm and I was hoping this would give fine enough control that I could just directly connect the motor to the mounting system
and aim the telescope without any extra gearing. As far as I've been able to work out, the encoder gives 4096 pulses per
rotation of the output shaft, which means we can aim it in 360/4096 = 0.08 degree increments. That is less than the field-of-view
so it would allow us to pick any object in the sky, but it is not a <i>lot</i> less than the field-of-view, which means it
wouldn't be able to track objects smoothly, so I'm going to have to gear this down a bit further.</p>
<p>The other part of imaging deep space objects is having good control over the camera. Mark suggests operating the PiKon
telescope by using <a href="https://www.raspberrypi.org/documentation/usage/camera/raspicam/raspistill.md">raspistill</a>
on the command line. Raspistill can draw a preview to the framebuffer device, and when you're happy with the shot you
can close the preview and run raspistill with different arguments to save a photograph to a file. This is fine for taking
pictures of the moon, but for more distant objects for which we're collecting less light, we need finer control.</p>
<p>I found Silvan Melchior's <a href="https://github.com/silvanmelchior/RPi_Cam_Web_Interface">RPi Cam Web Interface</a> software
and have played around with it a little. It seems to do pretty much exactly what I want, it just needs to be augmented with
controls for the motorised mounting system. It is a web interface to the
<a href="https://github.com/rpicopter/raspimjpeg">raspimjpeg</a> program, which can provide live previews while simultaneously
recording video or taking photos, and it can update the camera parameters without having to exit and reinitialise (like you
would have to do with raspistill), which saves a lot of time. This particularly saves time when taking long exposures, because
from what I read in <a href="https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=82306">this forum thread</a> the
Pi camera synchronises all of its setup around the exposure time. If the exposure time is 3 seconds, it takes about
3x 3 seconds
to initialise the camera, which is very annoying. Raspimjpeg keeps the camera running constantly so can just change settings
whenever the next exposure starts without wasting any time. Raspimjpeg does seem to lack raspistill's workaround to get maximum
exposure time up from 3 seconds to 6 seconds, but that's tolerable, especially with exposure stacking.</p>
<p>Exposure stacking is where you can approximate a 30-second exposure by taking 10x 3-second exposures and adding the resultant
images together. This has a key advantage over long exposures in that a.) if the object has moved slightly in the sky, you have
a chance to realign it after-the-fact, and b.) you can take images with longer exposures than the camera supports. The
downside of exposure stacking is that it amplifies noise as well as signal. I watched a tour of
<a href="https://www.youtube.com/watch?v=A0Tyrh5VqPc">the Isaac Newton Telescope</a> in which the operator took some photographs
of the sky at dusk, before the night's work began, called a "sky flat". He can then use the sky flat to calibrate what the
signal from the sensor looks like on a plain background, and use that to remove noise from the real photographs.
Another approach is to cover the end of the telescope so that no light is getting inside, to find out what the noise floor
of the sensor looks like absent any stimulation from light. I intend to experiment with both of these.</p>
<p>I have actually already built the telescope itself, and tested it out for the first time today. Here's a photograph of it:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1949"><img src="https://img.incoherency.co.uk/1949/thumb"></a></p>
<p>It uses 3 different colours of 3d-printed plastic because I happened to reach the end of first a grey and then a black spool of
filament. Still seems to be plenty of life left in the red/pink, unfortunately. The clamp around the middle of the tube is for
attaching it to the altazimuth mount
that I have not yet built (the clamp is roughly at the centre of mass of the telescope - the mirror is substantially
heavier than the camera and Raspberry Pi!). The circuit board on the side at the top is a Raspberry Pi Zero W. The ribbon cable goes down the
"mouth" of the telescope and connects to the camera, which is mounted on the other end of the red stick, and can be moved
in and out to focus the image using the grey knob. The bottom end of the telescope houses the concave mirror.</p>
<p>I managed to take
this awful picture of part of the moon by pointing the telescope out of my bedroom window:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1948"><img src="https://img.incoherency.co.uk/1948/thumb"></a></p>
<p>Since I don't yet have any kind of tripod or computer control, I have to aim it manually and try to hold it still. It is actually quite hard to even get the moon in the frame when you're only looking
at a quarter of a degree of the sky. You'll also note that it is not quite in focus. Once the telescope is focused it
should almost never need re-focusing, as looking at things in space basically just
wants it to be focused infinitely far away. However, I found that the focus knob on the PiKon is extremely sensitive, so I would
rather not have to set this up manually. Fine-tuning the focus electronically certainly sounds easier. Patrick used a
servo to drive a gear so that he could adjust this in software. I intend to do something similar. It doesn't need to be able
to move the focus knob through the entire range of its motion, as only a very small range is actually useful. The rest of it
could better be described as "calibration" than focus, i.e. it has lots of range in order to take up variations in the tube length
and mirror focal length.</p>
<p>My house is not a very good place to do astronomy as there is a lot of light pollution, buildings, and trees in the immediate
vicinity. My aim is to take the telescope to some remote-ish location, set it up outside, and control it from a laptop
inside my van. Since it would likely be at a different place each time (even if only slightly different), the altazimuth
tracking will need recalibrating each time. Probably the easiest way to do this is to aim it vaguely at the moon by eye,
then jog the axes until it is pointing at the centre of the moon, and then sync that to the coordinates that Stellarium says the
centre of the moon should be at. Afterwards, aiming it anywhere in the sky should line up correctly.</p>
<p>I've never electronically controlled a motor before, but I have
an L298N "dual H-bridge motor controller" and it was surprisingly easy to use. You just give it a power supply to send to
the motor, and then you have 2 pins for each motor: set 1 pin high and it runs forwards, set the other pin high and it runs
backwards, turn them both off and it stops. I haven't actually checked what happens if you set them both high, doesn't seem
advisable though. The built-in encoder on the gear motor uses a magnet and 2 hall effect sensors as a "quadrature encoder"
so that you can find out the direction and relative angle of the shaft. Once you've decided where you want the telescope to point,
you just have to work out how many steps of the quadrature encoder you need to pass through, and in which direction. I'm thinking I might use an Arduino to control the 2 motors and the focus servo, and just have the Raspberry
Pi send commands to the Arduino to tell it where to move. The reason is that the Arduino only runs a single program, so you
can guarantee that it won't be pre-empted by something else, causing it to miss some steps on the motor which would leave
the telescope pointing in the wrong place.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/pikon-telescope.html</link>
   <guid>http://incoherency.co.uk/blog/stories/pikon-telescope.html</guid>
   <pubDate>Mon, 19 Nov 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Deanonymising a Tor hidden service with traffic correlation</title>
   <description><![CDATA[We've all heard that Tor hidden services can be traced to an IP address by an attacker who has
sufficient visibility into global internet traffic, by correlating traffic sent to/from the hidden
service with traffic sent to/from real IP addresses.
But how easy is it in practice? How much data do you need? And how good do you need to be at statistics?
I decided to find out.]]></description>
   <content:encoded><![CDATA[<p>We've all heard that Tor hidden services can be traced to an IP address by an attacker who has
sufficient visibility into global internet traffic, by correlating traffic sent to/from the hidden
service with traffic sent to/from real IP addresses.
But how easy is it in practice? How much data do you need? And how good do you need to be at statistics?
I decided to find out.</p>
<p><h3>Overview</h3></p>
<p>In order to carry out the attack, you need to have a target hidden service, a set of suspected host machines
(in the limit case this can be "every machine on the internet"), and access to some information about the
networking each of those machines is doing.</p>
<p>This can range from "very easy" if you're the government and you only suspect a small number of machines, to
"impossible" if you're just an ordinary person and you have no suspects.</p>
<p>Since we're not the government, we'll have to cheat. I run a hidden service interface to this blog at
<b>jesblogfnk2boep4.onion</b>, for which I can obviously observe the networking. I also have several other
machines dotted around the internet, for which I can also observe the networking.</p>
<p>(I've put all of my files, including data, in <a href="https://github.com/jes/corr">a github repo</a> in case you want to play
with it yourself).</p>
<p><h3>Logging traffic counts</h3></p>
<p><tt>ifconfig</tt> gives us helpful statistics on networking activity:</p>
<p><pre><code>$ ifconfig -a
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet w.x.y.z  netmask 255.255.255.0  broadcast w.x.y.255
        inet6 fe80::aaaa:bbbb:cccc:dddd  prefixlen 64  scopeid 0x20<link>
        ether aa:bb:cc:dd:ee:ff  txqueuelen 1000  (Ethernet)
        RX packets 232310804  bytes 57245707805 (53.3 GiB)
        RX errors 0  dropped 4404528  overruns 0  frame 0
        TX packets 245582565  bytes 93237821276 (86.8 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0</code></pre></p>
<p>I wrote <a href="https://github.com/jes/corr/blob/master/log-tx-packets">log-tx-packets</a> to log packet counts.
It loops forever, sleeping until the top of the next second,
then shelling out to <tt>ifconfig</tt> to log the number of "TX packets" since the last sample. I chose "TX packets"
instead of "RX packets" because the size of an HTTP response is larger than the size of an HTTP request, so is likely
to result in a larger signal. "TX bytes" might work even better than "TX packets", I haven't tried it. This script
is to be run in <tt>screen</tt> on each of the suspect machines, with stdout going to a file.
It's also important that you synchronise the clocks
with <tt>ntpdate</tt> or similar before starting. If they're off by even a few hundred ms it might throw things off.</p>
<p><h3>Creating traffic</h3></p>
<p>So now we have second-precision logs of traffic counts available on each of our suspect machines, we need to start
making the hidden service produce some traffic that we know about. This is easily done with <tt>torsocks</tt> and <tt>curl</tt>:</p>
<p><pre><code>$ time torsocks curl -s http://jesblogfnk2boep4.onion/ > /dev/null</p>
<p>real    0m1.547s
user    0m0.160s
sys 0m0.433s</code></pre></p>
<p>I ran this a bunch of times, and it completed in 1.5 to 1.9 seconds each time. This means if we want to partition
our time such that 50% of timeslices have a request being handled, and 50% of timeslices have no request
being handled, our timeslices probably want to be 2 seconds. We could go back and modify <tt>log-tx-packets</tt> to
reduce the precision to 2 seconds instead of 1 second, but I just accounted for it later.</p>
<p>I next wrote <a href="https://github.com/jes/corr/blob/master/fetch-site">fetch-site</a> to make automated requests to
the hidden service. It loops forever, sleeping until the top of the next second, then shelling out to <tt>torsocks curl</tt>
to make a request to the hidden service, but only on seconds that are divisible by 4. Since we're using 2-second timeslices,
and want to send requests in 50% of timeslices, we only want to send a request every 4th second.</p>
<p>So with <tt>log-tx-packets</tt> already running in <tt>screen</tt>, I started <tt>fetch-site</tt> running on my laptop to
start trying to put some signal into the packet count logs.</p>
<p><h3>Processing the data</h3></p>
<p>Now we are getting a count of the packets transmitted each second by each machine, but this signal is way too noisy to
make any sense of by hand. But we can take advantage of the fact that making a request every 4th second should produce a
0.25 Hz signal on top of the ordinary networking traffic.</p>
<p>Consider a list of uniformly-chosen random numbers. If you keep an "accumulator" value, and add to the accumulator all of
the numbers
at even-numbered indexes in the list, and subtract from the accumulator all of the numbers at odd-numbered indexes
in the list, you would expect the accumulator to hover around 0.</p>
<p><blockquote>163-481+400-496+940-117+198-640+152-174 = -55</blockquote></p>
<p>And if we kept going further, it would still hover around 0.</p>
<p>However, in a list where the numbers at even-numbered indexes are slightly higher, you would expect the accumulator to
grow continuously over time, because the values that are being added can be expected to be higher than the values that
are being subtracted.</p>
<p><blockquote>263-481+500-496+1040-117+298-640+252-174 = 445</blockquote></p>
<p>(That's the same list, but with 100 added on to each of the added numbers, while the subtracted numbers remain the same). If we kept going further, it would keep growing larger.</p>
<p>Our log files of packet counts can be considered this way. If we add on the packet counts during even-numbered timeslices (i.e.
2-second periods during which we were doing a request), and subtract packet counts during odd-numbered timeslices, then
we can expect the accumulator of the machine that is hosting our hidden service to get large (since it does more networking
while we're making requests), while the others hover around 0.</p>
<p>In practice this scheme is thrown off by outlier timeslices during which unusually-large amounts of networking are done,
so let's also throw away any timeslices that are more extreme than the 95th percentile. We can also normalise the accumulator by
the mean packet size of the machine we're looking at, so that an accumulator of small numbers that is constantly growing isn't
dwarfed by an accumulator of large numbers hovering around 0.</p>
<p>So I wrote <a href="https://github.com/jes/corr/blob/master/score-log">score-log</a> to read in a packet count log
and compute the accumulator value as a score for how well the packet counts correlate with the hidden service requests.</p>
<p>I also wrote a shell script to <tt>scp</tt> the log files, and one to run <tt>score-log</tt> on each one.</p>
<p>After the first 5 minutes, we have:</p>
<p><pre><code>$ ./sync-logs && ./score-logs
scaryspice: -3.33789188491807
sportyspice: 17.5645714285714
babyspice: -0.645836662937511
gingerspice: 4.9340804218853
poshspice: -10.125</code></pre></p>
<p><tt>sportyspice</tt> has a larger accumulator than the others, but <tt>poshspice</tt>'s accumulator has a similar magnitude,
so we're probably still not picking up a signal above the noise.</p>
<p>After 30 minutes:</p>
<p><pre><code>$ ./sync-logs && ./score-logs
scaryspice: 7.66967566341574
sportyspice: 351.34283015898
babyspice: 13.447107176731
gingerspice: 5.10374373477445
poshspice: -105.243956043956</code></pre></p>
<p><tt>sportyspice</tt> still has a larger accumulator than the others, but <tt>poshspice</tt> still seems quite strongly
negatively-correlated.</p>
<p>I left it running overnight and after about 13 hours we have:</p>
<p><pre><code>$ ./sync-logs && ./score-logs
scaryspice: -53.2196414933282
sportyspice: 12387.0290996054
babyspice: 53.8562369567745
gingerspice: 201.901095205812
poshspice: -398.654982817869</code></pre></p>
<p>And, indeed, <tt>sportyspice</tt> corresponds to the machine that is hosting <b>jesblogfnk2boep4.onion</b>! That was easier than
I expected, it only took about 100 lines of code, almost no knowledge of statistics, and produced conclusive results in a matter of hours. It is admittedly pretty ghetto, but that just means a non-ghetto version would be even more effective.</p>
<p><tt>poshspice</tt> has
a surprisingly large and consistent negative correlation. Possibly it is doing
some networking of its own that has a period of 4 seconds, I've not looked into this.</p>
<p><h3>Improvements</h3></p>
<p>Probably the "correct" way to detect a 0.25 Hz signal is by taking a
<a href="https://en.wikipedia.org/wiki/Fast_Fourier_transform">Fast Fourier Transform</a> and looking for a peak
at 0.25 Hz. This is probably more reliable than my method.</p>
<p>We'd probably want a probability and a p-value, rather than a unit-less "score", if we wanted to be a bit more scientific.
More stats knowledge required for that.</p>
<p>Instead of choosing to send a predictable 0.25 Hz signal, we could choose at random, at each timeslice, whether or not
to fetch the site.
We just need to log which timeslices we were fetching, and use this information when computing the scores. This
would make it easier to differentiate our fetching from any other process that might have predictable timing, and might
get rid of examples like the phantom correlation that <tt>poshspice</tt> exhibited, although
it would make it incompatible with the FFT approach.</p>
<p>Instead of using short timeslices and only sending 1 request, we could use larger timeslices (say, a minute, or even an hour) and
make as many requests as we can get away with during that time. This would produce a much larger signal, as the machine
would be forced to do a lot more networking, at greater risk of our correlation attack being detected. This would also
make it comparatively less important that the traffic logs are labelled with accurate timestamps.</p>
<p>You could send almost-arbitrarily large amounts of data by sending a POST request with a very large body. If you did this,
and looked at "RX packets" instead of "TX packets", this might get a better signal-to-noise ratio, since most clients are
just sending simple GET requests.</p>
<p>Instead of making actual HTTP requests, we could probably just make a connection to the Tor instance hosting the
hidden service, but without going far enough in the request to cause it to propagate up to the application layer. This
would greatly improve our chances of avoiding detection as it would not create evidence in the web server log file. I don't
actually know how to do this, or whether it is possible in the general case.</p>
<p><h3>Practical considerations</h3></p>
<p>If the machine hosting the hidden service is very busy, you'll need to do more requests in order to pick out your signal above
the noise of its usual networking. This makes the attack take longer.</p>
<p>In practice the set of suspect machines is likely to be larger than 5, which again means you either need to create a stronger
signal, or have the attack take longer.</p>
<p>An ISP or hosting company could easily use this attack while monitoring the networking of a customer in order to determine
whether their customer is likely to be hosting a given hidden service.</p>
<p>It wouldn't only be the hosting machine that has traffic that is correlated with the hidden service: the Tor relays on the
route would also be correlated with it, so a real-world attacker might need to take that into account, depending on
how large the set of suspect machines is.</p>
<p>If you have enough control over the networking of a suspect machine, you could try switching it off for a few seconds and seeing
if that makes the hidden service unreachable. If the hidden service reliably goes down at times the suspect's networking
is switched off, that's a good indication that the suspect is hosting the hidden service. This is probably both easier
to carry out and more damning than the correlation attack, but more disruptive and has a higher chance of being discovered.  
Even if you don't have enough control over the networking of a suspect machine to switch its networking off yourself, you might
find some joy in
<a href="https://incoherency.co.uk/blog/stories/hardbin-phishing.html">sending an abuse report to the ISP and waiting for them to switch the networking
off for you</a>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/traffic-correlation.html</link>
   <guid>http://incoherency.co.uk/blog/stories/traffic-correlation.html</guid>
   <pubDate>Thu, 18 Oct 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to use Ricochet IM on Tails</title>
   <description><![CDATA[I've been using Tails (a privacy-focused Linux distro) as my day-to-day operating
system recently, and I was disappointed to find that Ricochet IM does not work out-of-the-box.]]></description>
   <content:encoded><![CDATA[<p>I've been using <a href="https://tails.boum.org">Tails</a> (a privacy-focused Linux distro) as my day-to-day operating
system recently, and I was disappointed to find that <a href="https://ricochet.im">Ricochet IM</a> does not work out-of-the-box.</p>
<p>(If you're interested in learning more about how Ricochet works, I wrote <a href="https://incoherency.co.uk/blog/stories/ricochet-im.html">a post about that</a> recently.)</p>
<p>Tails firewalls all access to the internet so that no application can accidentally do any non-Tor networking that might
give your identity away. Ricochet tries to run its own Tor process (separate to the system Tor process) in order to run its
hidden service. In the default configuration, this Tor process tries to access the internet directly, which is of course
blocked by the Tails firewall. This isn't a big problem, we just need to configure it to proxy via the system Tor process.</p>
<p>The problem is that when Ricochet starts its own Tor process,
it communicates with its control port using TCP over the loopback interface on an unpredictable port number.
In order to reduce the attack surface, the Tails firewall blocks all non-essential networking,
including access to the loopback interface.</p>
<p>My work-around for this was to add a firewall rule that allows the Tails user to access anything on the loopback interface.
<b>This weakens the Tails security model, so only do it if you're more interested in using Ricochet than having a secure system</b>.
Things that might be accessible over the loopback interface include the control port
for the system Tor process, so relaxing this rule is not to be taken lightly.</p>
<p><h3>Walkthrough</h3></p>
<p><h4>1. At boot time, enable the admin password</h4></p>
<p>You'll need an admin password both for installing Ricochet and for altering the firewall rules.</p>
<p>At the little login screen that Tails boots to, click the "+" under "Additional Settings", and set an administrator password.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1932"><img src="https://img.incoherency.co.uk/1932/thumb"></a></p>
<p><h4>2. Install ricochet-im</h4></p>
<p><pre><code>$ sudo apt update && sudo apt install ricochet-im</code></pre></p>
<p>This will take a little while, depending on how lucky you got with the Tor relay selection. Some are quite slow.</p>
<p>If you have <a href="https://tails.boum.org/doc/first_steps/persistence/index.en.html">encrypted persistent storage</a>
configured, and you want to use Ricochet more than once, you might want to choose "Install Every Time" when
Tails pops up a message asking you if you want it installed automatically every time the system boots.</p>
<p><h4>3. Allow the amnesia user to access anything on localhost</h4></p>
<p><pre><code>$ sudo iptables -I OUTPUT --out-interface lo --destination 127.0.0.1 --protocol tcp --syn --match owner --uid-owner 1000 --jump ACCEPT</code></pre></p>
<p><b>Again: This weakens the Tails security model, so only do it if you're more interested in using Ricochet than having a secure system</b>.</p>
<p>I copied most of this line from the default Tails rules, but remove the port number so it allows access to all ports.
Note that it begins <tt>-I</tt> rather than <tt>-A</tt>. This is because we need
this rule to be inserted at the start, so that it comes before the "default reject", instead of after.</p>
<p>The reason this has to allow access to every port rather than just one specific port is that Ricochet has its Tor process choose a control
port at random. Changing this to use a constant port number would be better for use on Tails, but
would require modification of the Ricochet source. It's a trivial modification! But it's not one that is shipped from apt,
so it's a bit inconvenient.</p>
<p><h4>4. Start Ricochet</h4></p>
<p>Either from the system menu:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1933"><img src="https://img.incoherency.co.uk/1933/thumb"></a></p>
<p>Or by running <tt>ricochet</tt> from a terminal.</p>
<p><h4>5. Configure Ricochet to proxy via the system Tor instance</h4></p>
<p>Our firewall change only relaxed access to localhost, so internet access still needs to be proxied via the system Tor process.</p>
<p>Select "Configure" instead of "Connect" at the Ricochet startup screen (if Ricochet starts without prompting, click the little
Settings icon and find the Tor settings). Then set the proxy to <tt>localhost:9050</tt>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1934"><img src="https://img.incoherency.co.uk/1934/thumb"></a></p>
<p>And then you should be up and running!</p>
<p><h4>6. Persistence</h4></p>
<p>The above is perfectly adequate for a throw-away Ricochet instance, but if you want to keep your contact list, keep a static
Ricochet ID, etc., you'll want to link it in to your
<a href="https://tails.boum.org/doc/first_steps/persistence/index.en.html">encrypted persistent storage</a>.</p>
<p>(If you don't already have encrypted persistent storage configured, but you want to use it, you'll have to work out how to do that on your own).</p>
<p><h5>6.1 Ricochet package</h5></p>
<p>Install <tt>ricochet-im</tt> and have Tails add it to the list of "Additional Software", if you haven't done so already.</p>
<p>Now every time you boot Tails with the persistent storage unlocked, Ricochet will be installed automatically. This takes quite a few
minutes, but Tails eventually pops up a dialog to tell you it is ready, and then it's accessible from "Internet" under the "Applications"
menu.</p>
<p><h5>6.2 Ricochet config</h5></p>
<p>In addition to installing the Ricochet program, you'll also want your Ricochet configuration to appear automatically.</p>
<p>I did this using the "dotfiles" feature of the encrypted persistent storage, so make sure you have that enabled (under "Applications",
"Tails", "Configure Persistent Volume"):</p>
<p><a class="img" href="https://img.incoherency.co.uk/1935"><img src="https://img.incoherency.co.uk/1935/thumb"></a></p>
<p>For the initial setup, we can just copy the Ricochet files into the "dotfiles" directory and then reboot the machine.
On subsequent boots, the files will be symlinked into place. Stop Ricochet first, to make sure the directory
is in a consistent state, and then:</p>
<p><pre><code>$ mkdir -p /live/persistence/TailsData_unlocked/dotfiles/.local/share/Ricochet/ricochet/
$ cp -a ~/.local/share/Ricochet/ricochet/* /live/persistence/TailsData_unlocked/dotfiles/local/share/Ricochet/ricochet/</code></pre></p>
<p>For avoidance of doubt: note that if you copy the Ricochet files into the "dotfiles" directory, and then start Ricochet again and add
some more contacts, those contacts will be gone next time you boot, because you only copied a snapshot of the config. Next time you
boot it will be a symlink so it will stay up to date on its own.</p>
<p><h5>6.3 Firewall rules</h5></p>
<p>I added a shell script under <tt>~/Persistent</tt> to setup the firewall rules:</p>
<p><pre><code>$ cat ~/Persistent/ricochet-firewall 
#!/bin/sh</p>
<p>sudo iptables -I OUTPUT --out-interface lo --destination 127.0.0.1 --protocol tcp --syn --match owner --uid-owner 1000 --jump ACCEPT</code></pre></p>
<p><h5>6.4 Usage</h5></p>
<p>When you want to use Ricochet, you need to boot Tails with the admin password enabled, so that you can setup the firewall rules. Tails
will automatically symlink in your Ricochet config, and will automatically install Ricochet. While it's installing Ricochet (or, right
before you want to use Ricochet), you can run:</p>
<p><pre><code>$ Persistent/ricochet-firewall</code></pre></p>
<p><b>Once more: This weakens the Tails security model, so only do it if you're more interested in using Ricochet than having a secure system</b>.</p>
<p>It will produce no output (other than prompting for the admin password), but the <tt>iptables</tt> rule will be added which will allow Ricochet to work.</p>
<p>So that's how I use Ricochet on Tails. Bit hacky, and it weakens the security a bit, but it works for me and maybe it will work for you too.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/ricochet-tails.html</link>
   <guid>http://incoherency.co.uk/blog/stories/ricochet-tails.html</guid>
   <pubDate>Sat, 13 Oct 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Hiding messages in chess games</title>
   <description><![CDATA[I designed a steganography system that encodes data as a chess game.
A convenient way to communicate chess games is PGN,
but any means of communicating the moves of the game would work, as the information is encoded conceptually in the
moves themselves, rather than taking advantage of any redundancy in the PGN format.]]></description>
   <content:encoded><![CDATA[<p>I designed a steganography system that encodes data as a chess game.
A convenient way to communicate chess games is <a href="https://en.wikipedia.org/wiki/Portable_Game_Notation">PGN</a>,
but any means of communicating the moves of the game would work, as the information is encoded conceptually in the
moves themselves, rather than taking advantage of any redundancy in the PGN format.</p>
<p>You can play with it here: <a class="btn btn-primary" href="https://incoherency.co.uk/chess-steg/">Chess Steganography</a>.</p>
<p>The code is <a href="https://github.com/jes/chess-steg">on github</a>. There is also a perl implementation of the same concept, but the encoding is incompatible because it was easier that way.</p>
<p>As an example, the text "Hello, world!" becomes:</p>
<p><blockquote>1. e3 b6 2. b3 Bb7 3. Nf3 Bxf3 4. Bd3 e6 5. h4 g6 6. b4 h5 7. gxf3 c5 8. Bb2 a5 9. Rh3 e5 10. c4 Bh6 11. Be2 Ke7 { White resigns. } 0-1</blockquote></p>
<p>You can look at this game <a href="https://lichess.org/Jo8s60AO">on lichess</a>, and copying and pasting the full PGN from lichess into the "Unsteg" box (despite lichess's annotations!) will allow you to retrieve the message.</p>
<p><h3>How it works</h3></p>
<p>First we encode the input data bytes as a bignum so that it's easier to work with. I prepended an imaginary "0x01" byte to the input
so that leading "0x00" bytes are not lost ("0x00 0x03" and "0x00 0x00 0x03" both become just "3" as a bignum; with a "0x01" at the start
they can be distinguished from a plain "0x03").</p>
<p>At a given turn, we generate the list of all legal moves. Discard any moves that would end the game (as that
might leave us unable to encode all of the data) and sort the moves so that we know we have a canonical ordering. For the first move, there
are exactly 20 legal moves.</p>
<p>If every turn had exactly 20 legal moves, we could easily encode the data in the chess game by encoding it as a base-20 number and then
choosing the move, for each digit, that corresponds to that digit.</p>
<p>The fun trick here is that the same scheme works even if the number of legal moves per turn is not constant! To remove the least-significant-digit
in base 20, we just take our bignum modulo 20, and then divide the bignum by 20 (truncating a fractional part, instead of rounding) before processing the next digit. This works just as well even if the base
is not constant. So for each turn of the game, we get to encode some amount of data based on how many legal moves were available. Each move is a "digit"
of the number in a variable-base numbering system, where the "base" at any given digit is dictated by how many legal moves there were.</p>
<p>So now we just loop until our bignum is zero, generating the list of legal moves at each turn, and consuming some of the bignum by encoding it
into a chess move. Having consumed the bignum, we can just pretend that the player who is supposed to move next resigned instead of playing a move,
and we have a complete chess game.</p>
<p>About 1 byte per move (or 4 bits per ply) is typical for short messages (which is about what you'd expect if you assume around 16 possible
moves per turn). For longer messages this gets worse, as the endgame tends towards having just the two
kings remaining on the board, where fewer possible moves are available.</p>
<p><h3>Worked example</h3></p>
<p>Let's try to encode the letters "JS".</p>
<p>As bytes, we have "0x4a 0x53". Since my implementation was little-endian by accident, we get "0x01 0x53 0x4a" after prepending the 0x01 byte. 0x53 = 83 and 0x4a = 74. This
corresponds to the number 86858 (1*256*256 + 83*256 + 74).</p>
<p>White's first turn of the game has 20 possible moves (sorted lexically):
  Na3, Nc3, Nf3, Nh3, a3, a4, b3, b4, c3, c4, d3, d4, e3, e4, f3, f4, g3, g4, h3, h4.</p>
<p>So we need to get the least-significant-digit of the base-20 representation of our bignum, which is 86858 % 20 = 18. The move with index 18 (starting from 0) is <b>h3</b>.
So white plays the move h3, and we divide our bignum by 20: 86858 becomes 4342.</p>
<p>Black's first turn of the game also has 20 possible moves. Black needs to play the move at index 4342 % 20 = 2. This move is <b>Nf6</b>. So black plays Nf6, and then
we divide our bignum by 20 again: 4342 becomes 217.</p>
<p>White's second turn has only 19 legal moves now, so now we need the least-significant-digit of the base 19 representation of what remains of our bignum.
Not a problem. 217 % 19 = 8, move 8 is <b>c3</b>. White plays c3, and we divide our bignum by 19 this time: 217 becomes
11.</p>
<p>Black's second turn has 22 legal moves. 11 % 22 = 11, move 11 is <b>b6</b>. Black plays b6 and we divide our bignum by 22: 11 becomes 0. Game over. It's white to
move, so white graciously resigns, and we have finished encoding the number 86858, which encodes our letters "JS":</p>
<p><blockquote>1. h3 Nf6 2. c3 b6 { White resigns. } 0-1</blockquote></p>
<p>It should be clear that the same scheme works for longer messages, and in practice I have found it works for messages that appear <i>way</i> too large, although a 600-move
chess game is obviously suspicious.</p>
<p>Decoding the message is the same process, but in reverse: instead of generating the bignum and then consuming it with chess moves, we build up the bignum from the chess moves
and then decode it into the raw bytes.</p>
<p><h3>Potential improvements</h3></p>
<p>My current implementation avoids checkmating, and ignores draw by repetition and the 50-move rule, but doesn't notice a stalemate. This is because detecting stalemate in <a href="https://github.com/jhlywa/chess.js/">chess.js</a> is a bit more annoying without simulating every possible
move at every turn, which makes it quite slow. The downside of this is that there is likely some set of data that cannot be encoded at all because it leaves
the game in a stalemated state, where there are no legal moves. Even if this were fixed, it is possible that the game could get into a state where there are legal moves,
but all of them are either checkmate or stalemate. After checkmate and stalemate moves are rejected, there would be no available moves to select from. In practice I've
not run into any of these conditions so far, avoiding checkmate seems to be good enough.</p>
<p>Also, the moves played in the games are quite likely to be complete blunders, as the algorithm has no idea what makes a reasonable or unreasonable move. It simply plays
moves based on whatever move encodes the data. You could encode data using quite-convincing moves if, instead of allowing selection from all ~20 moves per turn,
you limited it to only the moves that a chess engine doesn't consider to be blunders. This would make the games more convincing, at the cost of making them longer.
And you'd also need to come up with a reason that the engine plays good moves, but seems to miss every available checkmate.</p>
<p>The system as implemented involves a contrived game where both players' moves are chosen freely, but it could be extended to encode a message even when playing against
a player who is not complicit. It would work almost the same, but moves would need to be chosen on-the-fly because our list of legal moves depends
on what our opponent played. Once we've consumed our entire bignum, we simply resign.
This "one-sided" mode does have the problem that the other player might checkmate us before we've got our message across, however. A practical way to use it might be to have 
the sender set up a lichess account which the recipient knows about. Whenever the sender wants to send a message, he plays a game against anybody else on lichess,
encoding his message in the moves he chooses. (In the event that he gets checkmated before finishing the message, he just plays another game and tries again). The recipient
periodically checks this lichess account for new games (specifically, ones in which the sender resigned rather than getting checkmated), and decodes the moves
to retrieve the message.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/chess-steg.html</link>
   <guid>http://incoherency.co.uk/blog/stories/chess-steg.html</guid>
   <pubDate>Tue, 09 Oct 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Someone used my IPFS gateway for phishing</title>
   <description><![CDATA[At 02:43 this morning, I received an abuse complaint email. It was sent by PhishLabs to DigitalOcean,
and DigitalOcean forwarded it to me.]]></description>
   <content:encoded><![CDATA[<p>At 02:43 this morning, I received an abuse complaint email. It was sent by <a href="https://www.phishlabs.com/">PhishLabs</a> to DigitalOcean,
and DigitalOcean forwarded it to me.</p>
<p><blockquote>During an investigation of fraud, we discovered a compromised website (hardbin.com) that is being used to attack our client and their customers.</p>
<p>https://hardbin.com/ipfs/QmUyT6vFaGxgcyD7o7eX4eifvV5fVxxKyfSfNC8oP6JG1B/index.html#Login/XQAAAASQAAAAAAAAAAAeGgqG70rZWojk3J5AyyC5pdYwyJfWHIBHUGivJcLcQVE/oHjdV3pvUtyMRW499SqeMLLi7x4fSaIAi0Izhe+oGbBKFh28KmaEAtiTUDAZuJULtdxsBAqWIUpOddytlgEdBqFdM6cEiQ44qWXdB1OipKFu0hVNKIAA</p>
<p>First detection of malicious activity: 10-02-2018 19:06:26 UTC
Most recent observation of malicious activity: 10-02-2018 19:28:25 UTC
Associated IP Addresses:
178.62.243.230</blockquote></p>
<p>No "compromised website" here! The machine in question is my public <a href="https://ipfs.io/">IPFS</a> gateway, which I run for the purpose
of providing a convenient introduction to <a href="https://incoherency.co.uk/blog/stories/hardbin.html">hardbin</a>.</p>
<p>Around the same time that this email was forwarded to me, DigitalOcean disabled the network interface on my VPS in order
to stop the phishing attack from working. Fair enough, can't really expect them to do any more than that.</p>
<p>When I woke up and read this email, I visited the URL to verify that it is phishing, and immediately blocked the offending IPFS hash
(QmUyT6vFaGxgcyD7o7eX4eifvV5fVxxKyfSfNC8oP6JG1B) in my nginx config, and replied to DigitalOcean at 08:38 explaining
that I have blocked the hash and could they please switch my networking back on.</p>
<p>I decided to take a look at what exactly this phishing site was doing.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1928"><img src="https://img.incoherency.co.uk/1928/thumb"></a></p>
<p>So it's just a standard Google sign-in phish. Probably the victim receives an email telling them that they need to login to
their Google account in order to resolve a problem, and the hyperlink goes to the URL given above.</p>
<p>You'll note the URL has some random-looking text in the
URL fragment:</p>
<p><pre><code>#Login/XQAAAASQAAAAAAAAAAAeGgqG70rZWojk3J5AyyC5pdYwyJfWHIBHUGivJcLcQVE/oHjdV3pvUtyMRW499SqeMLLi7x4fSaIAi0Izhe+oGbBKFh28KmaEAtiTUDAZuJULtdxsBAqWIUpOddytlgEdBqFdM6cEiQ44qWXdB1OipKFu0hVNKIAA</code></pre></p>
<p>so our first guess might be that some of the content is encrypted to avoid detection, and this is a key
that then decrypts the content.</p>
<p>The HTML source is odd, however. It includes a mention of <a href="http://toast.bitty.site/">http://toast.bitty.site/</a>.
It turns out that "bitty.site" is a tool that allows you to encode the entire content of a small web page in the
URL fragment! And indeed, that is what is being done here.</p>
<p>The random-looking text in the URL fragment is actually the content of the page, compressed with LZMA and encoded with base64.
If we reverse this, we get:</p>
<p><pre><code>$ echo "XQAAAASQAAAAAAAAAAAeGgqG70rZWojk3J5AyyC5pdYwyJfWHIBHUGivJcLcQVE/oHjdV3pvUtyMRW499SqeMLLi7x4fSaIAi0Izhe+oGbBKFh28KmaEAtiTUDAZuJULtdxsBAqWIUpOddytlgEdBqFdM6cEiQ44qWXdB1OipKFu0hVNKIAA" | base64 -d | lzcat</p>
<p>&lt;html&gt;&lt;head&gt;&lt;script&gt;window.location.href='https://onedrivepreinhabitat.blob.core.windows.net/dropboxintroconverti/GMA.html?z=a';&lt;/script&gt;&lt;/html&gt;</code></pre></p>
<p>It seems all this is doing is redirecting to a file called <tt>GMA.html</tt> hosted in somebody's OneDrive folder.
Using Firefox "Network Tools" verifies that the site is indeed fetching content from this OneDrive URL (it's worth verifying this
even though it is pretty obvious, because otherwise a sneaky attacker could slip any plausible content into the URL
fragment in order to frame an innocent third-party).</p>
<p><a class="img" href="https://img.incoherency.co.uk/1929"><img src="https://img.incoherency.co.uk/1929/thumb"></a></p>
<p>I also compared the HTML content that my server was returning to the content generated by "bitty.site" and it was identical,
which proves there is nothing else up the attacker's sleeve.</p>
<p>So this is an interesting conundrum: since my server isn't actually returning any phishing content for the requested URL,
should I even be blocking it? The content returned by my IPFS gateway for this URL is just a generic HTML renderer. My server is no
more complicit in the phishing campaign than the user's web browser is! I reported my findings to DigitalOcean at 09:13
and asked if they would be happy for me to unblock the URL. There is certainly an <i>argument</i> that I shouldn't unblock
it, since blocking it demonstrably prevents the phishing attack. But it is also hard to argue that completely benign
content should be blocked just because somebody somewhere is phishing.</p>
<p>Interestingly, the source of the OneDrive URL actually checks whether the <tt>?z=a</tt> parameter is present. If so it
deobfuscates the page content using <tt>atob</tt>, and if not it
redirects via hardbin.com. I'm not sure why.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1930"><img src="https://img.incoherency.co.uk/1930/thumb"></a></p>
<p>I looked up the OneDrive URL in <a href="https://www.virustotal.com/#/url/590b589ce459051039548df59ee7261573ac91ef578bf20a64754f5a3abeaa54/detection">VirusTotal</a>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1927"><img src="https://img.incoherency.co.uk/1927/thumb"></a></p>
<p>Only 3 of the 70 anti-phishing companies are actually classifying this URL as a phish. That is surprisingly poor.</p>
<p>In the past I have been very impressed with DigitalOcean's abuse response
staff. I used to run a Tor exit node on DigitalOcean and they were extremely patient with me, so I was expecting my networking
to be switched back on promptly. However, by 7pm (nearly 11 hours after I blocked the URL in question) I
had still received no further correspondence from DigitalOcean. And my networking was still switched off.
This was very annoying.</p>
<p>My friend Miles Armstrong suggested taking a snapshot of the droplet and restoring it to a new droplet, and switching
the hostname over to point at the new droplet. I thought that was a splendid idea, so I did it, and 15 minutes later
hardbin.com was back online. Hurrah! I did inform DigitalOcean about what I'd done, but they still haven't replied about
that either.</p>
<p>So the problem is resolved for now, from my perspective (although I am still blocking a completely-benign IPFS hash,
which I don't feel good about). It's worth noting that the completely-malicious <tt>GMA.html</tt> file is <i>still</i>
not blocked by OneDrive (although <i>their</i> hosting provider doesn't appear to have switched <i>their</i> networking off).</p>
<p>I am surprised that the phisher decided to host the actual content on OneDrive instead of putting the entire phish in the URL
fragment. Given that OneDrive haven't been very proactive in taking it down, it seems to have worked out, but the site would certainly
be harder to take down if it only existed in the URL fragment.</p>
<p>And if you know a hosting provider that is less likely to switch your networking off, I'm all ears.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/hardbin-phishing.html</link>
   <guid>http://incoherency.co.uk/blog/stories/hardbin-phishing.html</guid>
   <pubDate>Thu, 04 Oct 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How Ricochet IM works</title>
   <description><![CDATA[Ricochet is instant messaging software that communicates over Tor, authenticates peers
by their Tor onion address, and communicates directly peer-to-peer (via Tor hidden services) without
any centralised servers involved.]]></description>
   <content:encoded><![CDATA[<p><a href="https://ricochet.im/">Ricochet</a> is instant messaging software that communicates over Tor, authenticates peers
by their Tor onion address, and communicates directly peer-to-peer (via Tor hidden services) without
any centralised servers involved.</p>
<p>Using Tor has lots of benefits over raw TCP:</p>
<p><ul>
<li>Doesn't leak metadata (all an observer can see is that you're using Tor)</li>
<li>Built-in peer authentication (peers are identified by a hash of their public key)</li>
<li>Direct peer-to-peer communication with no NAT traversal tricks required</li>
</ul></p>
<p>If you want to try out Ricochet, you can get it from <a href="https://ricochet.im/">ricochet.im</a>,
or from your Linux distro package manager. In Ubuntu:</p>
<p><pre><code>$ sudo apt install ricochet-im</code></pre></p>
<p><h2>Protocol overview</h2></p>
<p>The software is dead easy to use. You just add a contact
by their Ricochet ID, and when they're online you can chat. All of the underlying complexity is
abstracted away. But we're here to discuss
the underlying complexity:</p>
<p>When you want to speak to someone who is using Ricochet, you connect to the hidden service described by
their Ricochet ID on port 9878 (so <tt>ricochet:it2j3z6t6ksumpzd</tt> is equivalent to what would be called <tt>it2j3z6t6ksumpzd.onion:9878</tt> in
usual parlance). You then have to authenticate yourself to prove who you are (see "Peer authentication" below).
Having authenticated, you can now use this connection to send messages which will be delivered to the remote user, and the remote user can
send messages to be delivered to you. It's basically as simple as that.</p>
<p>You can read a more thorough description in the <a href="https://github.com/ricochet-im/ricochet/blob/master/doc/protocol.md">Ricochet protocol documentation</a>. Almost all of the
heavy lifting is palmed off to Tor. This is a good design and I think many other protocols
could benefit from it. For example, Bitcoin's Lightning Network would be more private and easier to configure
if it always used Tor hidden services instead of IP addresses
(i.e. you wouldn't have to write your IP address in the config file, or care if your IP address changes,
or configure port forwarding on a home router, or worry that your ISP can see that you're using Lightning, etc.).
The only downside of Tor-by-default is that it has high latency and low bandwidth, but for most
applications that is not a problem and the privacy and ease-of-use wins more than make up for it. There is
certainly low-hanging fruit to be eaten here.</p>
<p><h2>Peer authentication</h2></p>
<p>Most of the protocol is symmetrical, which means it doesn't matter which side of the connection is
the "server" and which side is the "client": both sides can send messages just the same.
Peer authentication is the only part that is not symmetrical.</p>
<p>When you connect to a Tor hidden service, you know you're talking to the right place. The onion address is
a hash of the hidden service's public key, so it is impossible for anybody who does not hold the corresponding
private key to decrypt the messages you're sending.</p>
<p>But when someone connects to your Tor hidden service, you have no idea who they are! Ricochet's answer to
this is to have both client and server generate a (one-time, random) 16-byte authentication cookie, and then have the client compute a SHA256 HMAC
of the concatenation of the client's and server's onion addresses, using the concatenation of the client's and server's cookies
as a key, and then sign this HMAC using the client's hidden service private key. The signature is then
passed to the server, who computes the same HMAC using the same parameters, and then verifies the signature.
If the signature checks out, then the client holds the private key that corresponds to the public key it presented.</p>
<p>The purpose of having the server generate a random cookie is to prevent replay attacks (i.e.
even if you manage to observe the unencrypted communication stream of a client authenticating with a server once, you can't
reuse that yourself to impersonate that client as the server will present a different cookie next time, and
you will need to produce a signature for the new HMAC). The <i>client's</i> cookie would not appear to serve
any security purpose.</p>
<p><h2>Practical attacks</h2></p>
<p>I briefly looked through the Ricochet source to see if there were any obvious mistakes in obvious places and
could not find any. It has also been <a href="https://www.nccgroup.trust/us/our-research/ricochet-security-assessment-public-report/">audited by NCC Group</a>.</p>
<p>A friend who is more of an expert on Tor than I am told me, after I asserted that Ricochet is as good as it is
possible for it to be, that he likes Ricochet but would like it more
if it used <a href="https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt">V3 hidden services</a>.
This is a less-trivial fix than it sounds because the peer authentication leverages the underlying
cryptography, but it would be possible to do and hopefully somebody will implement it one day.</p>
<p><h4>What can a man-in-the-middle see?</h4></p>
<p>A man-in-the-middle of your internet connection (say, your ISP) would be able to see that you're using Tor, but
not know anything else. In particular, they wouldn't even be able to find out whether you're using Ricochet,
other than by guessing based on inbound and outbound bandwidth usage. This is substantially better than
approximately all other instant messaging software. The
reason for this is that the underlying protocol is obscured (because Tor), and there are no instant messaging
servers to give the game away (because Tor hidden services; but even if there were Tor-based servers, the ISP
still wouldn't know you were using them, because Tor).</p>
<p><h4>Checking if someone is online</h4></p>
<p>If you know someone's Ricochet ID, then you can tell whether
they are online even if they do not accept your contact request. Simply try to initiate a connection to
their hidden service and see if it is available. If it is, they're online. If it's not, they're not.</p>
<p>There is unfortunately no obvious way to solve this problem as there is no way to know who is connecting to
your hidden service until after they've gone through peer authentication. But by the time they've gone through
peer authentication, they already know that you're online.</p>
<p><h4>Traffic correlation</h4></p>
<p>If you can observe somebody's internet traffic (say, you're their ISP) <i>and</i> you know a bunch of Ricochet
IDs that they might be using, you can repeatedly initiate connections to the Ricochet IDs and watch for corresponding Tor activity on
their internet connection. If it's reliably quiet while you're doing nothing, and busy while you're doing something, for 
a certain Ricochet ID,
then you can be quite sure that you have worked out their Ricochet ID.</p>
<p><h4>Malicious hidden service directories</h4></p>
<p>Tor hidden service directories are ordinary Tor relays that have been stable for long enough to get trusted as hidden
service directories. Hidden service directories get to find out onion addresses. Given an onion address, you
need only connect to that hidden service and try to speak the Ricochet protocol to find out whether it is a
Ricochet ID (and the same applies for any other application). For this reason, there are unfortunately a lot of malicious hidden
service directories which are set up for the express purpose of surveilling the Tor network.</p>
<p>There's not a lot you can do about this. And there's not too much reason to worry about it, as long as you
remember that just receiving a contact request from someone
doesn't mean that the person who sent the request found out your Ricochet ID through some legitimate means.</p>
<p><h2>Conclusion</h2></p>
<p>Ricochet IM is <i>almost</i> as good as it is possible for it to be. It doesn't leak any information at all about
who you're talking to or what you're saying. It only leaks a bare minimum of information about the fact that you're
using Tor. Even if somebody finds out your Ricochet ID, it is impossible to link it to a physical-world
identity without either tricking you into clicking a URL (thereby discovering your IP address, or implanting malware), or privileged
access to your internet connection with which to conduct some traffic analysis. The worst part about Ricochet
is that hardly anybody is using it, and I want to change that.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/ricochet-im.html</link>
   <guid>http://incoherency.co.uk/blog/stories/ricochet-im.html</guid>
   <pubDate>Tue, 18 Sep 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Please don't block Europe</title>
   <description><![CDATA[Yesterday the EU approved a "Copyright Directive", which includes a tax on
linking to other websites, and mandatory upload filters on all user-submitted content, to prevent
copyright infringement.]]></description>
   <content:encoded><![CDATA[<p>Yesterday the EU <a href="https://www.theverge.com/2018/9/12/17849868/eu-internet-copyright-reform-article-11-13-approved">approved a "Copyright Directive"</a>, which includes a tax on
linking to other websites, and mandatory upload filters on all user-submitted content, to prevent
copyright infringement.</p>
<p>There were comments on HN about simply blocking all web traffic from Europe, examples from just <a href="https://news.ycombinator.com/item?id=17967366">one thread</a>:</p>
<p><blockquote>I wonder how long until companies outside of Europe decide it's easier just to block all traffic from Europe in protest.</blockquote></p>
<p><blockquote>I already hit error 451 when trying to read some local news in US when browsing from Europe (I don't remember name of the page now). This happened after GPDR came into effect.</blockquote></p>
<p><blockquote>I see no way to host any kind of content under such jurisdiction and surely all non European content providers would just block the EU rather then take on a task that even giants like facebook and google can barely manage.</blockquote></p>
<p><blockquote>Fuck it, block Europe entirely. See how quickly the politicians there crawl back on their knees when they cant use Facebook to see their grandkids pictures.</blockquote></p>
<p>Please do not do this.</p>
<p>The idea is that blocking European internet users will make Europeans complain to their politicians so that eventually
the law is changed, and everyone can go back to the way things were. Instead, let's
just ignore the Directive. We don't need to allow politicians, who do such a rotten job of ruling the
physical world, to apply the same methods to our virtual world.</p>
<p>The internet is humanity's first opportunity to create a free and open space where everybody in the world can
communicate, collaborate, work, and trade with anyone anywhere, without prejudice, and without borders. Blocking
traffic from Europe will only harm ordinary people in Europe. Discriminating against people from any jurisdiction
(a la trade embargoes) is an unethical way to attain political goals, regardless of how noble those goals might be.</p>
<p>In <b>1996</b>, John Perry Barlow wrote in <a href="https://www.eff.org/cyberspace-independence">A Declaration of the
Independence of Cyberspace</a>:</p>
<p><blockquote>These increasingly hostile and colonial measures place us in the same position as those previous lovers of freedom and self-determination who had to reject the authorities of distant, uninformed powers. We must declare our virtual selves immune to your sovereignty, even as we continue to consent to your rule over our bodies. We will spread ourselves across the Planet so that no one can arrest our thoughts.<br><br>
We will create a civilization of the Mind in Cyberspace. May it be more humane and fair than the world your governments have made before.</blockquote></p>
<p>In many ways great progress has been made on this front. Since 1996, the proportion of the world with access to the internet
has <a href="https://en.wikipedia.org/wiki/Global_Internet_usage#Internet_users">increased from 5% to 50%</a>. The
internet is one of the greatest liberators of people the world has ever seen.
But we're in danger of moving backwards if we pay too much attention to what politicians are saying.</p>
<p>So instead of bowing to the demands of the Copyright Directive, and allowing politicians to insert themselves
as rulers of a virtual world in which they're not welcome, or to create divisions between us where none need exist,
let us simply ignore them. The internet doesn't respect borders (indeed, doesn't <i>have</i> borders) and
we should make every effort to keep it that way. Please don't block Europe.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/dont-block-europe.html</link>
   <guid>http://incoherency.co.uk/blog/stories/dont-block-europe.html</guid>
   <pubDate>Thu, 13 Sep 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to install Ubuntu 18.04 LTS on a Lenovo Ideacentre 310s</title>
   <description><![CDATA[Yesterday I was asked to install Ubuntu on a Lenovo Ideacentre 310s. I expected this to be
quite easy but it was not.]]></description>
   <content:encoded><![CDATA[<p>Yesterday I was asked to install Ubuntu on a Lenovo Ideacentre 310s. I expected this to be
quite easy but it was not.</p>
<p>When you first switch the computer on, a small message flashes up at the bottom left, but
only for a fraction of a second. It says something like "Press ENTER to interrupt startup".
If you manage to press ENTER during the small time window, you're taken to Windows 10's
"Recovery" mode. If you can't manage to hit the ENTER key in time, make sure to have it held down before you switch
the computer on, and keep it held down.
This Windows 10 Recovery mode is not really what I was after, but somewhere (possibly under "Advanced"
or similar?  Can't quite remember) there is an option to reboot into the setup menu. Do that.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1911"><img src="https://img.incoherency.co.uk/1911/thumb"></a></p>
<p>There is also an option in Windows 10's Recovery mode to boot from an alternative device, but I found this was not sufficient to
boot the Ubuntu installer. At least, not until you've changed some of the UEFI settings.</p>
<p>The menu you find when rebooting into the setup menu will look more like what you're expecting:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1912"><img src="https://img.incoherency.co.uk/1912/thumb"></a></p>
<p>Look through the menus and:</p>
<p><ul>
<li>Disable "Secure Boot"</li>
<li>Enable "CSM"</li>
<li>Change "Boot mode" to "Legacy"</li>
<li>Make sure your USB drive is near the top of the boot order</li>
</ul></p>
<p>"Secure Boot" prevents the computer from booting "unauthorised operating systems". Ubuntu supposedly
is "authorised", but I don't really want the computer to be the one deciding what is or isn't authorised,
and it can only cause trouble, so I switch it off. YMMV.</p>
<p>As far as I have been able to determine, "CSM" is a mode that makes UEFI emulate BIOS. Ubuntu is supposed to work with UEFI but BIOS emulation
is easier and more reliable. I think "Legacy" boot mode enforces this BIOS emulation even if the OS looks like
it might work with UEFI.</p>
<p>Now reboot the machine and it should boot the ISOLINUX boot loader from the USB drive, which looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1913"><img src="https://img.incoherency.co.uk/1913/thumb"></a></p>
<p>If you instead see this grub screen:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1914"><img src="https://img.incoherency.co.uk/1914/thumb"></a></p>
<p>then it means the computer has booted with UEFI instead of BIOS emulation. You might still be able to get
it to work (let me know if you do and I'll update this post!) but the way we did it was with BIOS and ISOLINUX.</p>
<p>When you see the ISOLINUX screen, keep pressing the up and down arrows until you get to a menu:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1915"><img src="https://img.incoherency.co.uk/1915/thumb"></a></p>
<p>If you don't press up or down arrows, the menu is silently skipped and the Ubuntu installer won't boot
properly and may or may not show an error message. The error message we got was along the lines of:</p>
<p><tt>[Firmware Bug]: cpu 0, invalid threshold interrupt offset 0 for bank 4, block 1 (MSR00000413=...)</tt></p>
<p>Don't know what that means.</p>
<p>At the ISOLINUX menu, press F6 and enable the options for edd=on, nodmraid, nomodeset. We initially
tried enabling all of the options indiscriminately out of desperation, and found that while it did boot and install, we were left with no
power management and no audio. "edd=on, nodmraid, nomodeset" was the set of options we settled on
that booted the system and caused no obvious side effects, but, e.g., nodmraid would seem obviously irrelevant.</p>
<p>Once you've enabled those options, you can boot the installer, install Ubuntu, and should have no further problems.</p>
<p>So if you already have a Lenovo Ideacentre 310s
and want to put Ubuntu on it, that's how to do it. But having used one, I found it quite slow, and I found the oddball
hardware combination annoying to deal with, so I don't recommend buying one.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/ubuntu-18.04-ideacentre-310s.html</link>
   <guid>http://incoherency.co.uk/blog/stories/ubuntu-18.04-ideacentre-310s.html</guid>
   <pubDate>Wed, 12 Sep 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Spelunking the Web Servers of the Lightning Network</title>
   <description><![CDATA[I've finally got around to playing with Bitcoin's Lightning
Network over the past couple of days. I managed to buy one of the "I got Lightning working and all I got was this
sticker" stickers from BlockStream's Lightning store, and I'm in the process of adding Lightning payment support to
SMS Privacy.]]></description>
   <content:encoded><![CDATA[<p>I've finally got around to playing with Bitcoin's <a href="https://en.wikipedia.org/wiki/Lightning_Network">Lightning
Network</a> over the past couple of days. I managed to buy one of the <a href="https://store.blockstream.com/product/lightning-sticker/">"I got Lightning working and all I got was this
sticker"</a> stickers from BlockStream's Lightning store, and I'm in the process of adding Lightning payment support to
<a href="https://smsprivacy.org/">SMS Privacy</a>.</p>
<p>Lightning Network's (current) method of operation involves every node knowing about every other node. That means it's
super easy to get a list of all the nodes on the network. So I did the obvious thing and made an HTTP request to every node for which I knew an IPv4 address, just to
see what was out there.</p>
<p>The initial requests were performed with <tt>curl -i http://<b>$ip</b>/</tt>. I later manually followed redirects where
applicable.</p>
<p>There were 1207 nodes in total and 229 of them responded to HTTP on port 80.</p>
<p><table border>
<tr><th>Category</th><th>Nodes</th></tr>
<tr><td>No response</td><td>978 (81%)</td></tr>
<tr><td>Default web server page</td><td>53 (4.4%)</td></tr>
<tr><td>Running nginx</td><td>120 (9.9%)</td></tr>
<tr><td>Running apache</td><td>74 (6.1%)</td></tr>
<tr><td>Personal page</td><td>47 (3.9%)</td></tr>
<tr><td>Business page</td><td>32 (2.6%)</td></tr>
<tr><td>Short cryptic message</td><td>14 (1.2%)</td></tr>
</table></p>
<p>(It sums to more than 100% because some nodes are counted in more than one category).</p>
<p>The "Personal" pages included blogs, software repositories, information about the server hardware,
Lightning Network donation forms, Lightning Network statistics, etc.</p>
<p>Most of the "Business" nodes were running websites for obviously-Bitcoin-related businesses, but a handful
were just ordinary non-technical business websites. I suspect in these cases the corporate
firewall redirects all HTTP traffic to the company home page, and some employee of the company happens to
be running a Lightning Network node, at work, behind the corporate firewall.</p>
<p>The "short cryptic messages" were messages like "Nothing to see here", "Check back later". I was
surprised that over 1% of nodes responded in this manner.</p>
<p>There were 4 nodes with a <tt>Server</tt> header indicating that they run nginx, but with
content claiming to be an Apache default page. I suspect this is caused by nginx sitting
as a reverse proxy in front of Apache rather than any attempt to deceive.</p>
<p>I found 2 nodes each that were running Nextcloud, Mastodon, SynologyNAS, or a Tor exit node.</p>
<p>And some of the most interesting pages included:</p>
<p><ul>
<li>Some company's internal email-deleting tool. Presumably not intended to be public, and with an interface that implies that
its mode of operation is SQL injection (it asks you to input some "database code" to select emails). I couldn't work out what company this belonged to so have unfortunately been unable
to inform them that this is public.</li>
<li>A seemingly-infinite stream of MP3-encoded silence. My bash loop that was running the <tt>curl</tt> invocations spent quite some time trying to download this one before I realised what was going on.</li>
<li>And a JSON dump of one Lightning Node's channel states, including channel balances, which is more info than is publicly available. Publicly, you only get to see channel capacities. Showing channel balances allows an attacker to repeatedly request the information and learn when, and by how much, this node's channel states have changed.</li>
</ul></p>
<p>107 of the nodes reported their OS in either the <tt>Server</tt> header or the page content:</p>
<p><table border>
<tr><th>OS</th><th>Nodes</th></tr>
<tr><td>Ubuntu</td><td>75 (70%)</td></tr>
<tr><td>Debian</td><td>16 (15%)</td></tr>
<tr><td>Windows</td><td>5 (4.7%)</td></tr>
<tr><td>Raspbian</td><td>4 (3.7%)</td></tr>
<tr><td>CentOS</td><td>2 (1.9%)</td></tr>
<tr><td>Gentoo</td><td>1 (0.9%)</td></tr>
<tr><td>Fedora</td><td>1 (0.9%)</td></tr>
<tr><td>Unix</td><td>1 (0.9%)</td></tr>
<tr><td>OpenBSD</td><td>1 (0.9%)</td></tr>
<tr><td>FreeBSD</td><td>1 (0.9%)</td></tr>
</table></p>
<p>I suspect CentOS is under-represented here as it does not report its OS out of the box. Probably the same applies to others too.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/spelunking-ln.html</link>
   <guid>http://incoherency.co.uk/blog/stories/spelunking-ln.html</guid>
   <pubDate>Wed, 29 Aug 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>A 4x4 chess puzzle</title>
   <description><![CDATA[Playing Isopath a lot recently led to a broader interest
in board games, which led to me playing a lot of go,
and particularly chess (you can add me on lichess, but I'm not very
good). I had a look at some single-player
variants of chess and played "Hippodrome" a few times but found it very easy, however it gave me an
idea for another possibility.]]></description>
   <content:encoded><![CDATA[<p>Playing <a href="https://incoherency.co.uk/blog/stories/isopath-intro.html">Isopath</a> a lot recently led to a broader interest
in board games, which led to me playing a lot of <a href="https://en.wikipedia.org/wiki/Go_(game)">go</a>,
and particularly chess (you can <a href="https://lichess.org/@/jstanley">add me on lichess</a>, but I'm not very
good). I had a look at some <a href="https://en.wikipedia.org/wiki/List_of_chess_variants#Single-player_variants">single-player
variants</a> of chess and played "Hippodrome" a few times but found it very easy, however it gave me an
idea for another possibility.</p>
<p><h2>The puzzle</h2></p>
<p>The idea is that a 4x4 board is randomly filled with the 16 pieces from an ordinary chess set, with pawns excluded. You then
alternate moving a white piece and then a black piece. Pieces move like in chess, but every turn must be a capture. The
game ends either when there is no legal move, or when the white king captures the final black piece on the 15th turn.
(I'm aware this isn't the kind of thing people normally expect of a "<a href="https://en.wikipedia.org/wiki/Chess_puzzle">chess puzzle</a>", but I didn't know what else to call it).</p>
<p><a href="https://incoherency.co.uk/chess-puzzle/"><img src="https://img.incoherency.co.uk/1897"></a></p>
<p>I wrote a web-based implementation of this puzzle using a hacked-up version of <a href="http://www.chessboardjs.com/">chessboardjs</a> to
render the 4x4 board and pieces.</p>
<p>Code <a href="https://github.com/jes/chess-puzzle">on github</a>.</p>
<p><a class="btn btn-lg btn-primary" href="https://incoherency.co.uk/chess-puzzle">Play it now</a></p>
<p><h2>Solving it</h2></p>
<p>I think there are around 41 billion unique starting positions. There are 16! = 2.1&times;10<sup>13</sup>
possible permutations of 16 unique pieces, but since knights, rooks, and bishops all occur twice
per colour, we can divide by 2<sup>6</sup>, leaving 3.3&times;10<sup>11</sup>. If we also factor out
rotations and mirrors, we can further divide by 8, leaving 4.1&times;10<sup>10</sup>, or about 41 billion.</p>
<p>It would be good to come up with a methodical way of solving these puzzles.</p>
<p>If you just play random legal moves, you'll usually find that the puzzle ends up in an unsolvable state with
3 or 4 pieces left. I've come across a few principles that help, but still don't have a general method
of solving.</p>
<p><h4>1. When you move a piece, no other piece will ever be able to occupy the square you moved it from</h4></p>
<p>Since every move must capture a piece, no piece can ever move on to an empty square, which means once you've
vacated a square, you can never occupy it again.</p>
<p><h4>2. The final move must be a capture by the white king</h4></p>
<p>This follows because every move is a capture, and the game ends when only the white king remains.</p>
<p>This position is unsolvable: <b>2K1/4/3k/4</b> (copy and paste into the "Board state" box to load it in the interface).</p>
<p><img src="https://img.incoherency.co.uk/1898"></p>
<p><h4>3. If the white king is ever left with no pieces adjacent to it, the position is unsolvable</h4></p>
<p>This follows from points 1 and 2. Since the king can only capture pieces adjacent to it, and we know a piece
can never occupy a square that is empty, if the white king is surrounded only by empty squares, it
is not possible for the white king to ever capture the final black piece that would end the game.</p>
<p>This position is unsolvable: <b>Bq1K/NR2/1R1Q/rknb</b></p>
<p><img src="https://img.incoherency.co.uk/1899"></p>
<p><h4>4. The penultimate move must be a capture by a black piece of a white piece that is adjacent to
the white king</h4></p>
<p>This follows from point 2. Since we know the final move is by white, we know the penultimate move is by black.
Since the final move begins with a black piece adjacent to the white king, and there's only one
black piece on the board, the previous black move must have moved that piece. Since all moves must be
captures, the previous black move must have been that piece capturing a white piece. Since the king
can only capture adjacent, the previous black move must have been that piece capturing a white piece
that was adjacent to the white king in order for the position to be solvable.</p>
<p>This position is unsolvable: <b>4/2Kr/4/3N</b></p>
<p><img src="https://img.incoherency.co.uk/1900"></p>
<p>Black is forced to capture the knight, leaving the king isolated.</p>
<p><h4>5. The move before the penultimate move must leave the white king adjacent to a white piece that can
be captured by the only remaining black piece</h4></p>
<p>This follows from point 4. We know the penultimate move must capture a white piece adjacent to the white king,
so we know the move before that must leave the position in a state where this is possible.</p>
<p>This can be achieved either by moving the king or the other white piece (at the point this move
is played, there are only 2 white pieces). It is possible to draw similar conclusions all the
way back to the beginning of the game, but the number of possible moves increases exponentially (maybe?) as you
go further back.</p>
<p>This position is unsolvable: <b>4/2qn/1K2/2N1</b></p>
<p><img src="https://img.incoherency.co.uk/1901"></p>
<p>Although either of the black pieces can be captured by white, neither move would leave the king adjacent to
the other white piece. That means after black has captured the other white piece next turn, the white king will
be left isolated.</p>
<p><h4>6. If we can find an efficient way to decide whether a position is solvable, that is easy to turn into a quick solving
algorithm</h4></p>
<p>Let's assume we have an oracle that can tell us whether a position is solvable. To decide what move to play,
we simply consider every legal move and ask the oracle whether the resulting state is solvable. If it is,
we play that move and then repeat.</p>
<p>This sounds superficially similar to a depth-first search, except it only ever has 1 level of backtracking so
completes in linear time. It is therefore suitable for carrying out by hand if the oracle is simple enough.</p>
<p>A first approximation is just to consider points 1 to 5 above, and make sure not to
play any turn that would leave the board in an obviously-unsolvable state. I'm interested
in hearing more simple rules that can disprove solvability of a position.</p>
<p><h2>Empirical analysis</h2></p>
<p>I wrote <a href="https://github.com/jes/chess-puzzle/blob/master/gosolve/solve.go">a go program</a> to solve
positions more efficiently than the Javascript version included in the user interface. The general algorithm
is the same (depth-first search over all legal moves until a solution is found),
but it uses 16-bit <a href="https://en.wikipedia.org/wiki/Bitboard">bitboards</a> to represent the occupied squares,
and lookup tables to calculate legal moves. It's a bit hacky and not user-friendly but should serve as a good base if you want to
do some similar analysis.</p>
<p>Of several million random starting positions I tested, every single one was solvable.</p>
<p>I then wondered how many turns you could play at random without creating an unsolvable position. There's
no point wasting time reasoning about the first few turns if any legal move would work just as well.
I made the program ignore backtracking for the first <i>N</i> turns (i.e. play at "random" for <i>N</i> turns, and only
then start backtracking).</p>
<p>I ran the program on 1 million random starting positions for each value of <i>N</i>, with the following results.</p>
<p><table border>
<tr><th>Turns played at random, <i>N</i></th><th>Pieces remaining on board after <i>N</i>  turns</th><th>Probability of having a solvable position after <i>N</i> random turns</th></tr>
<tr><td>0</td><td>16</td><td>100%</td></tr>
<tr><td>1</td><td>15</td><td>100%</td></tr>
<tr><td>2</td><td>14</td><td>&gt;99.999%</td></tr>
<tr><td>3</td><td>13</td><td>99.6%</td></tr>
<tr><td>4</td><td>12</td><td>98.6%</td></tr>
<tr><td>5</td><td>11</td><td>93.2%</td></tr>
<tr><td>6</td><td>10</td><td>83.9%</td></tr>
<tr><td>7</td><td>9</td><td>65.1%</td></tr>
<tr><td>8</td><td>8</td><td>49.0%</td></tr>
<tr><td>9</td><td>7</td><td>29.7%</td></tr>
<tr><td>10</td><td>6</td><td>20.0%</td></tr>
<tr><td>11</td><td>5</td><td>9.80%</td></tr>
<tr><td>12</td><td>4</td><td>7.70%</td></tr>
<tr><td>13</td><td>3</td><td>4.85%</td></tr>
<tr><td>14</td><td>2</td><td>4.85%</td></tr>
<tr><td>15</td><td>1</td><td>4.85%</td></tr>
</table></p>
<p>From the 1 million positions tested, all of them were solvable after a random first turn. Only 3 of the 1 million
positions were unsolvable after a random second turn.</p>
<p>One of the 3 positions was <b>Nbrn/kqQB/nNRR/rbBK</b>:</p>
<p><img src="https://img.incoherency.co.uk/1902"></p>
<p>If you happen to take the black bishop with the white queen, and then take the white queen with the black rook,
you end up with <b>Nr1n/kq1B/nNRR/rbBK</b>:</p>
<p><img src="https://img.incoherency.co.uk/1903"></p>
<p>which has no solution.</p>
<p>For practical purposes, you can play the first 5 turns at random and still usually have a solvable position (93%).
With each turn played, reasoning about the position becomes easier. Although it is still too hard for me, in
the general case, with 11 pieces still on the board.</p>
<p><h2>Further work</h2></p>
<p>It would be nice if the user interface accepted a "difficulty" setting. We could come up with some algorithm
for scoring how difficult a position is (probably based on how sensitive it is to the choice of moves made early
on), and then generate starting positions at random until we find one of approximately the desired difficulty.</p>
<p>More progress towards a methodical solving system would also be useful.</p>
<p>Testing against 1 million positions gives a good idea of the numbers for solvability, but the go program is fast enough that it
could probably solve all 41 billion unique starting positions in only a day or so if anybody cared to make it
do that (you can factor out rotations by enforcing that the white king starts in the top-left quadrant; factoring out mirroring is maybe
trickier but would only get another factor of 2 so maybe you can ignore it). I'd be fascinated to see if there are a tiny number of unsolvable starting positions.</p>
<p>The links again: you can play it at <a href="https://incoherency.co.uk/chess-puzzle/">https://incoherency.co.uk/chess-puzzle/</a>
and view the code at <a href="https://github.com/jes/chess-puzzle">https://github.com/jes/chess-puzzle</a>.</p>
<p>Let me know if you have anything to say or ask about the chess puzzle, I'd love to hear from you.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/chess-puzzle.html</link>
   <guid>http://incoherency.co.uk/blog/stories/chess-puzzle.html</guid>
   <pubDate>Tue, 28 Aug 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>We entered the BLMRA 12 hour lawnmower race again</title>
   <description><![CDATA[After last year's poor show at the 12 hour, we
did some much-needed work on the mower and had another go.]]></description>
   <content:encoded><![CDATA[<p>After last year's <a href="https://incoherency.co.uk/blog/stories/blmra-12-hour-2017.html">poor show at the 12 hour</a>, we
did some much-needed work on the mower and had another go.</p>
<p><h2>Preparation</h2></p>
<p>The showstopper last year was that the steering kept collapsing. So this year's big project
was to build a new steering system from the ground up. None of the original steering components
are retained.</p>
<p>The steering wheel is connected to a shaft which, via a series of universal joints, exits horizontally, pointing
straight forwards, on the underside of the mower.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1776"><img src="https://img.incoherency.co.uk/1776/thumb"></a></p>
<p><small>(the mower is standing on end here; the stumps at left and right are spindles for the front wheels)</small></p>
<p>There is an arm coming off the shaft, to which the track rods are attached. When the steering wheel is turned, the
shaft rotates, and the arm rotates, which moves the track rods left and right. The other ends of the track rods
are attached to the stub axles, which I made on the lathe:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1721"><img src="https://img.incoherency.co.uk/1721/thumb"></a></p>
<p>Having turned up some kingpins, this then involved drilling an off-axis hole through the centre of the kingpin, which the spindle gets welded into. I
made a small jig to hold the kingpin off-axis in the lathe, and then used a holesaw to bore the hole. (The reason the
spindle is welded in off-axis is so that the steering axis is inclined, which causes the steering to tend to self-centre
when coming out of a turn, and
reduces the <a href="https://en.wikipedia.org/wiki/Scrub_radius">scrub radius</a>, making the steering lighter.
In reality I suspect it would handle largely the
same even if it was at 90 degrees, but it's the thought that counts.)</p>
<p><a class="img" href="https://img.incoherency.co.uk/1722"><img src="https://img.incoherency.co.uk/1722/thumb"></a></p>
<p>The kingpin bearings are a pair of M20 rose joints on each side, which are bolted to the large crossmember
which is welded to the chassis, and finally the wheels are fitted to the spindles.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1780"><img src="https://img.incoherency.co.uk/1780/thumb"></a></p>
<p>The steering system on the mower is the biggest mechanical engineering project I've ever done, and I'm pleased with the end result,
although despite my best efforts the geometry is best described as "anti-<a href="https://en.wikipedia.org/wiki/Ackermann_steering_geometry">Ackermann</a>" rather than the "true Ackermann" that I was
aiming for (i.e. the outside tyre actually scribes a tighter circle than the inside tyre does!).</p>
<p>From Wikipedia:</p>
<p><blockquote>Some racing cars use reverse Ackermann geometry to compensate for the large difference in
slip angle between the inner and outer front tyres while cornering at high speed. The use of such
geometry helps reduce tyre temperatures during high-speed cornering but compromises performance in
low-speed manoeuvres.</blockquote></p>
<p>So at least our tyres won't be over-heating...</p>
<p>Other improvements this year include a padded rail around the seat to keep our bums from falling off, a mesh rail around the
foot plates to keep our feet from falling out, better lights, and a new paint job.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1845"><img src="https://img.incoherency.co.uk/1845/thumb"></a></p>
<p>We arrived at the circuit on the Friday, the day before the start of the race, set up our pit, and
waited for everything to kick off.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1882"><img src="https://img.incoherency.co.uk/1882/thumb"></a></p>
<p>We had Emma helping out in the pits this year, bringing the total team to <a href="https://projects.argh.in/">Feroz</a>, <a href="https://curbedambition.com">James</a>, and
me driving, with <a href="https://caconym.co.uk">Matt</a>, Emma, and my Dad working in the pits (which is timing, refuelling, and, most importantly, repairing).</p>
<p><h2>Scrutineering, practice and qualifying</h2></p>
<p>Scrutineering was at 10am which we once again passed with only minor changes required to the mower.</p>
<p>We had to reverse some screws which according to the scrutineer "would rip someone's flesh out", and
we had to move the transponder as the timing gear wasn't picking it up very well, then it was just
a short wait before practice.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1876"><img src="https://img.incoherency.co.uk/1876/thumb"></a></p>
<p>We'd lowered the gear ratio since last year, as we'd found it way too high for last year's rough conditions. However, this year's
field was comparatively smooth, and we quickly learnt in the practice session that we were over-revving the engine before
reaching even halfway down the straights. So the decision was made to up the gearing. The gearing is changed
by changing the front pulley on the belt drive, but due to the way the belt is prevented from falling off our mower, changing the 
pulley is not a quick operation. So we cut our practice session short and set about changing the pulley.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1873"><img src="https://img.incoherency.co.uk/1873/thumb"></a></p>
<p>It was eventually
ready to go again shortly after the qualifying session started, so while we did miss out on some practice time, we still
had plenty of time to put in some qualifying laps. We eventually qualified in 26th place, of 43, which is 1 place better than last year.</p>
<p>We then had a few hours to rest before the start of the race. During this time the organisers put a <i>lot</i> of water down
on the track. This is ostensibly to keep the dust down, but Feroz theorises that it is also designed to cause a lot of
crashes to give the spectators a bit more of a spectacle.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1874"><img src="https://img.incoherency.co.uk/1874/thumb"></a></p>
<p><h2>Racing</h2></p>
<p><a class="img" href="https://img.incoherency.co.uk/1875"><img src="https://img.incoherency.co.uk/1875/thumb"></a></p>
<p>The race was a Le Mans-style start again, in which racers line up opposite their mowers, and then when the flag drops they run to
their mower, start it up, and set off. This year we again got a very good start, and I was running about 11th on the first lap.</p>
<p>Our anti-Ackermann steering geometry works very well when cornering hard in dry conditions, because the inside tyre doesn't touch
the ground anyway, as this picture from our last test session shows:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1872"><img src="https://img.incoherency.co.uk/1872/thumb"></a></p>
<p>However it is not quite as good in wet conditions, like the opening laps of the race, because it is not possible to load up the
outside tyre before it starts sliding. <a href="https://photos.google.com/share/AF1QipOtILyZiBKnwVtLFTr40fdJy_OObVUGWc62a0NIKUidFxsY8zDfCQL4lCXAUjMi9g/photo/AF1QipNrNEKMM_12mZHZ8_nnv57bs7Kb6Shw6BZjDQF-?key=djh4UnF6MGJ4M2dqeEUxT1JqMW80WGxUMExhRDdR">Here's a video</a> of me entering the hairpin too fast and under-steering straight into the barrier.</p>
<p>There were (predictably) a lot of mowers spinning out, crashing, and otherwise losing control at the start of the race. I avoided
most of the accidents that happened in front of me, but on about the third lap I spun out on the turn before the pit straight. I
looped around and was ready to rejoin the circuit when the engine cut out. I tried to re-start it but it was obvious that the
clutch was not disengaging, and it turned out that the clutch cable had come off. This was not a good sign. We hadn't even run
for 10 minutes before we were pushing the mower back to the pit.</p>
<p>A few minutes later, with a new clutch cable fitted, I rejoined the circuit as the sun was starting to set:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1881"><img src="https://img.incoherency.co.uk/1881/thumb"></a></p>
<p><small>(note the lengths of the shadows, and the driver shielding his eyes with his hand)</small></p>
<p>We had no issues for about the next 6 hours, which was better than any of us could have expected.</p>
<p>Things were going well in my third hour-long stint, until one lap I clattered around the hairpin a bit too hard, bouncing on 2 wheels, and shortly after that
the rear left tyre went flat. I pitted and we changed the tyre.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1880"><img src="https://img.incoherency.co.uk/1880/thumb"></a></p>
<p>Then a couple of laps later the front left tyre went flat. Pitted and changed
it, and then the belt flipped around and got a bit damaged. Pitted and put a new belt on, and now it was James's turn to drive. I had
fitted the belt retention rollers incorrectly and the new belt got damaged and came off quite quickly. Another new belt on,
with the rollers fitted correctly this time, and the other new belt came off quite quickly as well. This was our darkest hour.
Everything seemed to be going wrong at once and I didn't think we'd be able to keep it all working for another 6 hours.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1883"><img src="https://img.incoherency.co.uk/1883/thumb"></a></p>
<p>My Dad observed that the clutch mechanism was bent and the pulleys on it were misaligned, so he straightened it out, we put the belt back on, and sent
James back out again. He completed his first lap and all seemed well, then two laps, then three, then four, and we began to
relax once more. Everything was going well again.</p>
<p>And, amazingly, that was all! We had no further issues. I deliberately drove a bit more conservatively during my final stint, to avoid creating problems.
I was eventually pleased to find myself driving directly into the sun once more, in the opposite direction this time, as the sun started to rise around 5.30am.</p>
<p>At 7am on Sunday morning we sent Feroz out for the final stint of the race, and at 8am he completed our final lap. We finished in 20th place, having completed
299 laps, or 227 miles.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1879"><img src="https://img.incoherency.co.uk/1879/thumb"></a></p>
<p>20th place is a fantastic result. Much better than we should have been, judging by the lap times of the teams immediately surrounding us. The only reason
we did so well is because we had relatively few issues and were able to stay on the track, putting laps in, almost continuously for
the entire 12 hours. Reliability is the name of the game.</p>
<p><h2>Next year</h2></p>
<p>I'm feeling much more enthusiastic about next year than I was this time last year. In order to improve in position we'll need to
be putting in faster laps, which probably means reducing weight, improving the steering geometry, further lowering the
centre of gravity, and gaining confidence that it won't start falling apart as we start pushing harder.</p>
<p>We also need to make the clutch more robust so that it doesn't bend, and get better wheels so that the tyres don't
keep going flat when bouncing around corners on 2 wheels.</p>
<p>Here's an image showing how much force "Les's Lux Pussies" (the race winners) are able to put on their tyres without causing punctures (note the
deformation of the outside front tyre):</p>
<p><a class="img" href="https://img.incoherency.co.uk/1878"><img src="https://img.incoherency.co.uk/1878/thumb"></a></p>
<p>And finally, my Dad has been sizing up his own mower for a potential group 2 entry:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1865"><img src="https://img.incoherency.co.uk/1865/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/blmra-12-hour-2018.html</link>
   <guid>http://incoherency.co.uk/blog/stories/blmra-12-hour-2018.html</guid>
   <pubDate>Sat, 11 Aug 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I tried to make a vinyl record on the lathe</title>
   <description><![CDATA[In order to produce sound, a record player needle needs to ride in a track that has a tiny physical model of the waveform
of the sound.]]></description>
   <content:encoded><![CDATA[<p>In order to produce sound, a record player needle needs to ride in a track that has a tiny physical model of the waveform
of the sound.</p>
<p>A poor cut on the lathe can produce "chatter", which causes a wavy surface, accompanied with
some sounds. I think it's likely that the wavy surface is a physical model of the waveform of the sound (i.e. the sound
is caused by the cutting tool bouncing back and forth).</p>
<p>Looking at it the other way, the tool imparts an image into the work piece which is a mirror of the sound the tool
is making. So let's play some loud sound on the tool holder, cut a spiral into a piece of plastic, and then
see what it sounds like on the record player!</p>
<p>I cut out a rough circle of acrylic (which I suppose would make this an acrylic record rather than a vinyl record),
drilled a hole near the middle, and put a bolt through it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1868"><img src="https://img.incoherency.co.uk/1868/thumb"></a></p>
<p>I mounted the bolt in the lathe and tried to take a facing cut to flatten the surface. Unfortunately the acrylic is
nowhere near rigid enough. It was just tearing and flexing. But since the plastic flexes out of the way when the cut is too
deep, we can probably get away without a facing cut. So I stopped the facing cut halfway along and began the real cut.</p>
<p>Ideally the cut would be performed with the lathe turning at 33 rpm so that the music will be recorded at the correct rate
for playback on the record player. My lathe only goes down to 100 rpm so I went with that. To cut a spiral into the surface
of the plastic, the tool needs to be advanced across the face by at least 1 tool width per revolution, which is easily done by hand
at 100rpm.
The pitch of the spiral is not important since the needle of the record player just follows wherever the track goes.</p>
<p>The tricky part is applying sound to the tool so that it vibrates in and out to create our audio track.
I placed my mobile phone on the carriage while playing <a href="https://www.youtube.com/watch?v=nHs2sQOHX-0">Don't Mug
Yourself by The Streets</a> at full volume (the idea being that some of the sound will be transmitted to the
tip of the cutting tool) and cut a spiral into the face of my "record":</p>
<p><a class="img" href="https://img.incoherency.co.uk/1869"><img src="https://img.incoherency.co.uk/1869/thumb"></a></p>
<p>(The mess towards the outside is the attempted facing cut).</p>
<p>I tried to play this on the record player but found that:</p>
<p>a.) I had cut the spiral backwards. Starting from the outside, the needle is pushed off the record rather than carried into the
centre.</p>
<p>b.) The needle on the record player can't actually reach the centre of the record, it stops about 35mm out.</p>
<p>I could "play" the sound for about 3 revolutions by starting the needle towards the centre, which did produce sound but
it didn't sound like The Streets. It sounded more like the noise the cutting tool made.</p>
<p>So I flipped my record around and had another try, with no attempted facing cut. I ran the lathe backwards this time
so that the spiral would be in the right direction.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1870"><img src="https://img.incoherency.co.uk/1870/thumb"></a></p>
<p>The cut went well, although it isn't quite deep enough in some places. I tried to play this "A-side" in the record player
but, other than spinning in the right direction and having more usable area, it was no better than the first attempt.</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/p8KbFF3O8ws" frameborder="0" allow="encrypted-media" allowfullscreen></iframe></p>
<p>You're trying to pick out "Don't Mug Yourself" playing at about 1/3rd speed. I'm not confident any of it can be picked out
over the noise.</p>
<p>I suppose the real test will be whether I get a copyright strike from YouTube...</p>
<p>Even more than most of my projects, this project was a failure. To make it work you'd need to:</p>
<p><ul>
<li>Use a different type of tool, to cut the plastic without chattering, to reduce the noise in the track.</li>
<li>Get a more direct connection between the speaker and the tool, to increase the amount of signal in the track.</li>
<li>Use a bigger lathe. The circle I cut out is as big as I can fit on the lathe and it's not big enough for a record.</li>
</ul></p>
<p>I think it could be made to work, since this is essentially all a "real" record lathe does.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/homemade-record.html</link>
   <guid>http://incoherency.co.uk/blog/stories/homemade-record.html</guid>
   <pubDate>Thu, 09 Aug 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>What's inside an HSBC SecureKey?</title>
   <description><![CDATA[You've probably seen an HSBC SecureKey. It's a 2-factor authentication device for online banking.
I was given one because the previous owner had
started using the bank's smartphone app and no longer needed the SecureKey. It looks like this:]]></description>
   <content:encoded><![CDATA[<p>You've probably seen an HSBC SecureKey. It's a 2-factor authentication device for online banking.
I was given one because the previous owner had
started using the bank's smartphone app and no longer needed the SecureKey. It looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1822"><img src="https://img.incoherency.co.uk/1822/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/1823"><img src="https://img.incoherency.co.uk/1823/thumb"></a></p>
<p>I'm not sure if the numbers on the bottom left of the case back are sensitive. I surmise that they must
not be sensitive, otherwise that would transform the 2FA device from "something you have" into merely "something you know".
If the numbers are sensitive, please let me know rather than using them for evil :).</p>
<p>The red stuff around the edges is a plastic case. With no obvious seam, I thought the case halves must be ultrasonically
welded together to prevent tampering.</p>
<p>I peeled off the front and back stickers to see what we're working with.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1825"><img src="https://img.incoherency.co.uk/1825/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/1824"><img src="https://img.incoherency.co.uk/1824/thumb"></a></p>
<p>The "case" is not a clamshell at all! It's just a one-piece skeleton that everything is attached to.
The insides are only separated from the outside by the stickers.</p>
<p>There are some interesting holes in the back of the case, with some gold-coloured
stuff underneath, but at this point I couldn't work out what they were for.</p>
<p>The PCB has some holes in it, and some plastic from the case has been smooshed (?) around the holes to
retain the PCB. I tried
to remove the board by prying at it with a knife, but it was retained quite well and I think I must have broken something:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1826"><img src="https://img.incoherency.co.uk/1826/thumb"></a></p>
<p>Pressing the buttons no longer has any effect, it just lights (darks?) every cell of the LCD and does nothing else.</p>
<p>So for my next trick I used a hot soldering iron to remove the smooshed bits of plastic:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1827"><img src="https://img.incoherency.co.uk/1827/thumb"></a></p>
<p>(with the battery still in place, you understand, because it can't be removed until the board is removed from the case)</p>
<p>And then prying the board out with a knife was much more successful.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1828"><img src="https://img.incoherency.co.uk/1828/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/1829"><img src="https://img.incoherency.co.uk/1829/thumb"></a></p>
<p>The case has some cutouts in it for the components that are mounted on the board, presumably to
keep the device as thin as possible. The circuit board is also extremely thin. This
is probably why I damaged it so easily when prying at it earlier.
It is about 0.5mm thick, or about 2 <a href="https://www.answers.com/Q/What_is_the_average_thickness_of_a_human_hair">moustache hair's</a> diameters.</p>
<p>Here it is compared to an Arduino Nano, which weighs in at nearly 2mm:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1830"><img src="https://img.incoherency.co.uk/1830/thumb"></a></p>
<p>Back to the interesting side of the circuit board:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1829"><img src="https://img.incoherency.co.uk/1829/thumb"></a></p>
<p>The traces are gold-plated, which is a surprise. Possibly to help conductivity because they're so thin.
Apart from that, there's almost nothing to see here. The battery takes up over a quarter of the board. There are a handful
of resistors and capacitors. One transistor. A crystal oscillator. And a bunch of exposed gold-plated pads, mostly labelled
"TPxx". These
are "test points", and they line up with the holes in the plastic case, so that explains what the holes were for.</p>
<p>The 2x3 grid of pads near the middle is likely to be for JTAG access. If I knew how to communicate with (over?) JTAG
(and if I hadn't
broken the board earlier) it might have been interesting to play with this.</p>
<p>So the only thing left is the epoxy-topped "chip on board". This is a bare silicon die placed directly on the board,
without any packaging, and then epoxied in place. It would be interesting to look inside.</p>
<p>I've never decapped a chip before, but there's a first time for everything. I tried to read up on how to do
it and it mostly involved scary talk of very strong acids which I didn't like the sound of. I eventually
found <a href="https://www.youtube.com/watch?v=hQ5hXEK35WI">this video</a> wherein Kai Bader decaps an
IC with just a heat gun and a scalpel. Unlike using acid, this process destroys the bond wires (and
probably scratches up the die too much) so the chip will never
be made to work again, unless you're a wizard. But I was under no delusions about that anyway.</p>
<p>I found it more convenient to use a soldering iron than a heat gun, but the process went much the same as
depicted in Kai's video. Just keep heating and cutting and scraping until the die is fully exposed.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1835"><img src="https://img.incoherency.co.uk/1835/thumb"></a></p>
<p>You can see a surprising amount of detail on the die using just the camera from a smartphone. It's nowhere
near <a href="https://zeptobars.com/en/">ZeptoBars</a> level, but it's a better start than I expected.</p>
<p>It would be cool to get a more detailed shot than this, so I went on eBay and bought myself a "1600X Zoom
8 LED USB Microscope Digital Magnifier Endoscope Camera Video w/Stand" from a seller called
"beauty.city329". The "1600X" turned out to be optimistic by a factor of at least 100.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1836"><img src="https://img.incoherency.co.uk/1836/thumb"></a></p>
<p>I crossed my fingers and tried to get Linux to understand how to talk to it, and surprisingly got it working
quite quickly. (I just had to install a couple of packages from apt, but I can't quite remember what they were.)</p>
<p>This is what my setup looked like:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1821"><img src="https://img.incoherency.co.uk/1821/thumb"></a></p>
<p>I took the clear lens cover off because it was preventing the lens from getting close enough to the die.</p>
<p>The USB microscope focuses on a very small area (especially at zoom levels nearing the heady heights of 16x...) so it
was quite difficult to position the die in the frame properly. It was also quite difficult to focus the image since the microscope
has an extremely short focal length, although it thankfully does have a manual focus. This is the first picture I managed
to get:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1810"><img src="https://img.incoherency.co.uk/1810/thumb"></a></p>
<p>It's a little bit more detailed than the smartphone managed to get, but... not <i>much</i> more detailed. I don't
know whether this says more about cheap smartphone cameras or about cheap USB microscopes.</p>
<p>I played around for some time and took a handful more pictures of the die:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1811"><img src="https://img.incoherency.co.uk/1811/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/1812"><img src="https://img.incoherency.co.uk/1812/thumb"></a></p>
<p>The 2 green parts in the first picture are the same part as the 2 orange parts in the second picture (the colours
change as the light changes). The aspect ratio of
the camera in the microscope is clearly not very accurate.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1813"><img src="https://img.incoherency.co.uk/1813/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/1819"><img src="https://img.incoherency.co.uk/1819/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/1818"><img src="https://img.incoherency.co.uk/1818/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/1820"><img src="https://img.incoherency.co.uk/1820/thumb"></a></p>
<p>Not really enough detail to make anything out (at least, not to my untrained eye). Somebody who knows
more about integrated circuits might be able to identify the 2 large rectangles, I suspect
they're memory of some sort.</p>
<p>Anyway, there we have it. That's what's inside an HSBC SecureKey.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/hsbc-securekey.html</link>
   <guid>http://incoherency.co.uk/blog/stories/hsbc-securekey.html</guid>
   <pubDate>Thu, 12 Jul 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Introduction to Isopath</title>
   <description><![CDATA[Isopath is a game invented by YouTube user pocket83.
The game was initially presented in this video
where pocket83 shows how he made the board and tiles, and then explains the game rules from 15:45 onwards.
Isopath is a zero-sum, turn-based, deterministc, perfect-information game, which puts it in the same class
as games like chess, draughts, go, noughts-and-crosses, etc.]]></description>
   <content:encoded><![CDATA[<p>Isopath is a game invented by YouTube user <a href="https://www.youtube.com/user/pocket83">pocket83</a>.
The game was initially presented in <a href="https://www.youtube.com/watch?v=Wz6q03b8R6U&t=15m45s">this video</a>
where pocket83 shows how he made the board and tiles, and then explains the game rules from 15:45 onwards.
Isopath is a zero-sum, turn-based, deterministc, perfect-information game, which puts it in the same class
as games like chess, draughts, go, noughts-and-crosses, etc.</p>
<p>I 3d printed a few sets for myself and some friends, and we've enjoyed playing it.
If you like this sort of game, you should try a few rounds of Isopath. I think you'll like it too.</p>
<p><a href="https://isopath.jes.xxx/"><img src="https://img.incoherency.co.uk/1791"></a></p>
<p>Over the last week I've been working on a browser-based implementation of Isopath, which you can play at
<a href="https://isopath.jes.xxx/">https://isopath.jes.xxx/</a>.
You can play with a friend either locally or
over a websocket connection, or you can play
against an AI locally. There are 2 AIs available at the moment, one just plays random moves, and
the other is a relatively-serious effort, but not good enough to beat a human who knows
its weaknesses.</p>
<p><h2>Rules</h2></p>
<p>The gist is that two players each have 4 pieces on a hexagonal game board, starting at the
edges on opposite sides.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1787"><img src="https://img.incoherency.co.uk/1787/thumb"></a></p>
<p>One player
can only move on top of stacks of 2 tiles, and the other player can only move on
the bottom. In each turn a player moves one of their pieces to an adjacent location
that is at the correct height, and moves any free tile to any other location on the board.
The game ends when one player places a piece in the opponent's home row.</p>
<p>That's not quite all, you can learn the full rules either from pocket83's video, from his rule sheets
(<a href="https://postimg.cc/image/5sin82q1f/">sheet 1</a>, <a href="https://postimg.cc/image/yjfgy4vv7/">sheet 2</a>, <a href="https://postimg.cc/image/p05s4o8cz/">sheet 3</a>) , or from <a href="https://isopath.jes.xxx/#rules">my
write-up of the rules</a>. You'll get a better feel for the rules by playing the game.</p>
<p><h2>Notation</h2></p>
<p>It's helpful to be able to unambiguously identify the spaces on the board. For this reason, I propose labelling
the tiles as in this image:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1785"><img src="https://img.incoherency.co.uk/1785/thumb"></a></p>
<p>(i.e. the rows are labelled a to g, and the cells within each row are labelled starting with 1 at the left, from white's view).</p>
<p>White always starts on the 'a' row.</p>
<p>For correspondence play (and otherwise), in order to write down the sequence of moves made in the game, we need
a move notation. Pocket83 didn't suggest any notation to use, so I am using a capital letter to signify the
move part type ('T' for tile, 'P' for piece, 'C' for capture) and then either 1 or 2 coordinates to signify
the affected tiles.</p>
<p>For example, moving a tile from a1 to b5 would be "Ta1b5", and capturing a piece at d3 would be "Cd3".</p>
<p>For the sake of consistency, I also
propose standardising that white always moves first (this does not affect the nature of the game as everything
is symmetrical). A representative
game might look like:</p>
<p><b>1.</b> Td7b3 Pa2b3, Tf3d6 Pg2f3 <b>2.</b> Tc6c4 Pb3c4, Te3e4 Pf3e3 <b>3.</b> Td1d4 Pc4d4, Tf4d5 Pg3f3 <b>4.</b> Te5e2 Pa3b3, Td3d2 Pe3d3 <b>5.</b> Tc1c3 Pb3c3, Tc2d1 Pd3c2 <b>6.</b> Te1b1 Pa1b1, Pc2c1 Ta2c6 <b>7.</b> Tc6b5 Pa4b5, Pf3e3 Ta3e1 <b>8.</b> Tb4c5 Pb5c5, Pg4f4 Td6e6 <b>9.</b> Tb2c2 Pc5c4, Pf4e5 Td6e1 <b>10.</b> Tf2f4 Pc4d5, Pg1g4 Tf4d7 <b>11.</b> Tf5c2 Pc3c2, Td1d3 Pc1d1 <b>12.</b> Tc4d3 Pc2d3, Tb5c4 Pe5d6 <b>13.</b> Ce3 Tf1b4, Tb5b4 Pd6c6 <b>14.</b> Td2g3 Pd4e4, Ta4b2 Pc6b5 <b>15.</b> Te6c1 Pe4d4, Ta4b2 Pb5a4, black wins.</p>
<p><h2>Tactics</h2></p>
<p>Now we get to the meat of what I wanted to talk about.</p>
<p>(Some of the examples are rather contrived and exaggerated, in order to best demonstrate the principles, but never mind that; the
principles still apply in normal gameplay).</p>
<p><h4>1. A piece can not be stopped from advancing at 1 tile per turn, on a path that has all of the tiles at the correct height,
except by threat of capture</h4></p>
<p><a class="img" href="https://img.incoherency.co.uk/1794"><img src="https://img.incoherency.co.uk/1794/thumb"></a></p>
<p>With black to play here, there is nothing black can do to prevent white from winning.
Black can remove a tile from white's path each turn, but white can immediately put it back and progress 1 further tile.</p>
<p>Although the spaces g1 and g4 are considered adjacent, black can't teleport from g4 to g1 because white has already placed a tile on g1 (which black is not allowed to remove because it's
on his home row).</p>
<p>Black's only chance would be to move 2 of his pieces to threaten capture somewhere along the path. Threatening capture of g1 is
no use, because by the time white is on g1 he's already won the game. He can't threaten capture of f1 because he can only get 1
piece adjacent to it. Threatening capture of e2 would work, but it will take black 4 turns to get 2 pieces adjacent to e2,
by which point white will already be on e2 and will be able to move off e2 before getting captured. Threatening capture of d3
and c3 will also take 4 turns, but white will get past them even earlier.</p>
<p>If black does attempt to threaten e2, we reach something like this position, with white to play:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1795"><img src="https://img.incoherency.co.uk/1795/thumb"></a></p>
<p>White simply restores the tile on f1, steps on to f1, and then wins in the following turn.</p>
<p><h4>2. A piece can advance at 1 tile per turn, on a path that has all of the tiles at the middle height, except where explicitly stopped</h4></p>
<p><a class="img" href="https://img.incoherency.co.uk/1798"><img src="https://img.incoherency.co.uk/1798/thumb"></a></p>
<p>With black to move.</p>
<p>Black was paying attention last time, and knows that his 5-turn path from f4 to a4 can't be stopped by white.
However, white's path from c1 to g1, while not at white's full tile height, is potentially 1 turn shorter than black's path if
black plays poorly.
If black single-mindedly moves
his piece towards a4 without concern for which tiles he moves on the board, he'll find that white is
able to continue placing 1 tile and moving his piece 1 space per turn, and white will reach g1, winning the game
for white, immediately before black is able to step on to a4.</p>
<p>Black should remove the tile from d2 in his first turn, forcing white to move his piece to d1 if he wants to make progress.
Black should then remove the tile from e1, leaving white unable to make progress:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1796"><img src="https://img.incoherency.co.uk/1796/thumb"></a></p>
<p>Black's best path is now shorter than white's, and black wins the game. (Black could have captured white's piece on e6 on
either his second or third turn, but
doing so conveys no advantage here. It would mean forgoing either one tile movement or one piece movement, but black
would still be able to block white's progress and would still win the game).</p>
<p><h4>3. It's easier to threaten capture in the middle of the board than at the edges</h4></p>
<p><a class="img" href="https://img.incoherency.co.uk/1800"><img src="https://img.incoherency.co.uk/1800/thumb"></a></p>
<p>Black to move.</p>
<p>Black has a path from e6 to a4 that is at his height, so he can't be stopped except by threat of capture. White also
has a path from d2 to g2 that is at his height, and white's path is one turn shorter. Unfortunately, white's defensive
formation is much weaker than black's, because it does not adequately protect the edges of the board.</p>
<p>The only way white can threaten capture of black's piece as it heads towards a4 is if white can move one of the
pieces from b4 or d6 to
c5. Therefore black's move is to remove the tile from c5 and start moving towards a4:</p>
<p><ul>
<li>If white responds by trying
to block black's progress towards a4, black can just remove the tile and proceed.</li>
<li>If white responds by trying to restore the tile
on c5, black can again remove the tile and proceed.</li>
<li>If white ignores black's progress and tries to head
along his (shorter) path from d2 to g2, black can move a piece on to f3, threatening f2, and then continue heading towards
white's home row and win the game.</li>
</ul></p>
<p><h4>4. The row immediately in front of your home row is very vulnerable</h4></p>
<p>Once your opponent has a piece on the row immediately in front of your home row, your only way to stop him from winning the game
is to threaten him with capture (or to physically have a piece in the way). If you can't, or don't, put him under threat this turn,
then he will win. On his next turn he alters
a space on your home row by 1 tile, and you can't capture him because you didn't put him under threat last turn. On his turn
after that he finishes altering your home row and wins:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1806"><img src="https://img.incoherency.co.uk/1806/thumb"></a></p>
<p>White to move. By this point it's too late for black to stop white from winning. White moves a tile on to f2 and moves
the piece from e2 to f2. He's now on the row immediately in front of black's home row, so black's only way to stop him is to
threaten him with capture. Black can't do that this turn because his pieces are too far away, but he can take 1 step towards.
On white's turn he places the first tile on g2 and moves a random piece other than the one on f2. Black can now get close
enough to put f2 under threat, but on white's turn he places the second tile on g2 and wins.</p>
<p>Black should have noticed this coming sooner and made sure either not to have his pieces so far away, or to defend
the vulnerable row to stop white from being able to step on to it.</p>
<p>(As an aside, I think 2 players who persistently defend this row will end up in a stalemate that neither player
can break without losing the game. I'm not sure how the rules could best be tweaked to avoid this, or if doing so
is even beneficial).</p>
<p><h4>5. There's no need to fully develop any space on your opponent's home row until the final move that wins you the game</h4></p>
<p>As soon as you have altered a space on your opponent's home row by 1 tile, and because players aren't allowed
to touch the tiles on their own home rows: a.) your opponent can no longer stand on that
space, for the rest of the game, and b.) your opponent can not undo your building work.</p>
<p>Since every turn consists of 2 parts, you will
always be able to perform the final tile move to fully develop your winning space during your final winning move. Therefore, to
fully develop any space on your opponent's home row, before the move that wins the game for you, is to rob yourself of
one tile move earlier in the game.</p>
<p>(Of course, if
any other possible tile move would weaken your position, it's perfectly reasonable to use your opponent's home row instead.
But that's rarely, if ever, the case).</p>
<p><h4>6. Forcing a capture by threatening escape routes</h4></p>
<p>If you threaten an opponent with capture, and you also manage to threaten his only escape route, then you can force a capture of
his piece.</p>
<p>Here's a position that came up in a game between the AI (white) and me (black), with black to move:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1805"><img src="https://img.incoherency.co.uk/1805/thumb"></a></p>
<p>I moved the piece from d5 to c4, to step along the shortest path to a4, expecting white to respond by moving
the piece from a2 to b3. I hadn't
noticed the "pincer movement" available to white. He moves the piece on to d4, threatening both the black piece
and the black piece's escape route:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1802"><img src="https://img.incoherency.co.uk/1802/thumb"></a></p>
<p>And from there black has no way to save the piece on c4, because the only immediate escape is threatened, and any
other escape route will take at least 2 turns to move on to.</p>
<p>If black had brought forward the piece from f3 sooner, threatening d4, that would have prevented white from
being able to move on to d4, making it safer for black to move on to c4. White could still move on to c3 to threaten c4,
but black would at least be able to avoid the forced capture.</p>
<p><h2>Puzzle</h2></p>
<p>White to move and win in two:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1808"><img src="https://img.incoherency.co.uk/1808/thumb"></a></p>
<p>(<i>To be clear:</i> black's home row is at the top).</p>
<p><h2>More</h2></p>
<p>That's all for now. I hope you enjoyed it. I have developed quite the obsession with Isopath recently,
and I think you will too if you give it a try.</p>
<p>In the future I intend to write some more about tactics, and also
about the challenges in writing an AI, and promising approaches.</p>
<p>Please get in touch if you want to talk about Isopath, play Isopath, or write an AI to play Isopath:
<a href="mailto:james@incoherency.co.uk">james@incoherency.co.uk</a>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/isopath-intro.html</link>
   <guid>http://incoherency.co.uk/blog/stories/isopath-intro.html</guid>
   <pubDate>Sat, 30 Jun 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>My homemade ebike control panel</title>
   <description><![CDATA[I wrote before about dismantling the control panel from my ebike to find out how it works, and had some ideas for an improved design.]]></description>
   <content:encoded><![CDATA[<p>I wrote before about dismantling the control panel from my ebike to <a href="https://incoherency.co.uk/blog/stories/ebike-3-mode-pas-led-display-wiring.html">find out how it works</a>, and had some ideas for an improved design.</p>
<p>Specifically, I wanted:</p>
<p><ol>
<li>Easily set the desired power setting when switching the system on, without having to wait or do multiple button presses</li>
<li>Continuously-variable power setting, instead of just 3 modes</li>
<li>Fine-grained battery meter, instead of just 4 LEDs</li>
<li>Change the power level without looking at the display</li>
</ol></p>
<p>And I had some plans involving an Arduino Nano and a 160x128 LCD display.</p>
<p>I wrote most of the code while waiting for parts to arrive, then assembled it on a breadboard and took it outside to test on
the bike.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1744"><img src="https://img.incoherency.co.uk/1744/thumb"></a></p>
<p>To my dismay, the display was practically invisible! The backlight is switched on, and adjusted optimally. That's just
as bright as it gets in direct sunlight.</p>
<p>The display I ended up settling on is an 84x48 Nokia 5110 LCD. It is very clearly visible even in direct sunlight, so I rewrote
the Arduino code to work with the Nokia LCD, modelled an enclosure in FreeCAD
to mount the electronics on the handlebar, 3D printed it, sanded it, primered it (I used a filler primer, and lots of intermediate
sanding steps), and painted it. I epoxied a thin piece of acrylic glass into the front, and assembled it all on the bike.</p>
<p>CAD model:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1766"><img src="https://img.incoherency.co.uk/1766/thumb"></a></p>
<p>After printing, sanding, and primer:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1746"><img src="https://img.incoherency.co.uk/1746/thumb"></a></p>
<p>Painted:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1749"><img src="https://img.incoherency.co.uk/1749/thumb"></a></p>
<p>Gluing in the acrylic glass:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1751"><img src="https://img.incoherency.co.uk/1751/thumb"></a></p>
<p>Some more pictures:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1748"><img src="https://img.incoherency.co.uk/1748/thumb"></a> <a class="img" href="https://img.incoherency.co.uk/1752"><img src="https://img.incoherency.co.uk/1752/thumb"></a> <a class="img" href="https://img.incoherency.co.uk/1753"><img src="https://img.incoherency.co.uk/1753/thumb"></a> <a class="img" href="https://img.incoherency.co.uk/1757"><img src="https://img.incoherency.co.uk/1757/thumb"></a> <a class="img" href="https://img.incoherency.co.uk/1756"><img src="https://img.incoherency.co.uk/1756/thumb"></a></p>
<p>(The top and bottom halves of the enclosure just slide together and can be prised apart by hand; the tape inside is just to avoid any accidental shorts between the circuit boards.)</p>
<p>I am quite happy with the magnet pickup, and the handlebar clamp, and the finishing technique (while time-consuming) produces a good result. But the actual
design of the enclosure is very boxy and obviously homemade, which is not what I wanted. And unfortunately if the edges were more
rounded it would be even larger than it already is as it's built down to the dimensions of the circuit board the LCD is mounted on.</p>
<p>With my fancy new ebike control panel, I set off for my first proper test ride. In hindsight I should have done this <i>before</i>
spending all of that time and effort on building and painting the enclosure. I discovered that my continuously-variable "throttle" input
did not result in a continuously-variable pedal assist setting. It turns out the motor controller only supports 3 distinct
modes. Disaster!</p>
<p>I put up with it for a little while, and even had an opportunity to test it in the rain, which worked fine (never doubted it!):</p>
<p><a class="img" href="https://img.incoherency.co.uk/1760"><img src="https://img.incoherency.co.uk/1760/thumb"></a></p>
<p>But with only 3 distinct modes, and a smooth lever as the input, it's impossible to know when you're going to move from one mode to
the next. I modified the software so that the throttle lever indicator on the screen steps between 3 levels so you can at least
tell which mode you're in by looking at the screen, but this is not much improvement on the system the bike had before.</p>
<p>It was around this time that I read <a href="https://nomasters.io/posts/unquantified/">Unquantified</a>, which is
about reducing the amount of data in your life, and just being content with not knowing. It's good.</p>
<p>This convinced me that I didn't actually need the speedometer or the odometer, and at that point the only thing the display is good for
is the battery level, and maybe we could do without that as well. After all, if the battery runs out, it's not the end of the
world. An ebike with a flat battery just becomes an ordinary bike!</p>
<p>So I designed a much simpler, purely analogue, control scheme. I bought a "3 pole 4 throw" rotary switch off eBay. A "2 pole 4 throw" switch would do, but
is harder to find, or even a "1 pole 3 throw" if you're content with having a separate power switch. I wired it up so that in one position the "K" wire is disconnected from "VCC", and in the other 3 positions
"K" is connected to "VCC", and "TUO" is connected to a point in a voltage divider made of 3 5K resistors and a 10K resistor.
That gives a 1v drop across each of the 5K resistors, which gives us the 2v, 3v, and 4v
levels needed to select the different pedal assist modes. Here's a
schematic to explain what I mean:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1768"><img src="https://img.incoherency.co.uk/1768/thumb"></a></p>
<p>"A" and "B" are the common terminals of the rotary switch, with "1" to "8" being the corresponding switched terminals.</p>
<p>I used an LM7805 linear regulator to drop the battery voltage to 5v. For a higher-current circuit this would be an unreasonable
voltage drop and would both waste power and cause the LM7805 to get really hot, but since this is essentially just a
25 KOhm resistor, it hardly draws any current.</p>
<p>This was simple to make on a small piece of stripboard:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1765"><img src="https://img.incoherency.co.uk/1765/thumb"></a></p>
<p>and this time I went with a simpler enclosure before wasting time on painting:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1769"><img src="https://img.incoherency.co.uk/1769/thumb"></a></p>
<p>I've only ridden it a couple of times with this new switch, but am happy with it so far. I'd like to make a more elegant
control knob (the knob on it at the moment is just the thumb lever from my first attempt at a control panel), and a neater
enclosure, with labelled knob positions and a proper handlebar clamp, but it's pretty much there.</p>
<p>So how well did I meet my initial goals?</p>
<p><ol>
<li>Easily set the desired power setting when switching the system on, without having to wait or do multiple button presses: <b style="color:green">Success</b></li>
<li>Continuously-variable power setting, instead of just 3 modes: <b style="color:red">Impossible without replacing the motor controller.</b></li>
<li>Fine-grained battery meter, instead of just 4 LEDs: <b style="color:red">There's no longer any battery meter at all.</b></b></li>
<li>Change the power level without looking at the display: <b style="color:green">Success.</b></li>
</ol></p>
<p>I suppose 2 out of 4 ain't bad.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/ebike-control-panel.html</link>
   <guid>http://incoherency.co.uk/blog/stories/ebike-control-panel.html</guid>
   <pubDate>Fri, 01 Jun 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>A Rock-Paper-Scissors AI that is too good</title>
   <description><![CDATA[Yesterday I had an idea for a simple Rock-Paper-Scissors AI based on Markov chains. The "state" would be what the opponent played
in the last N rounds, and would be used to predict the probability that the opponent would play Rock, Paper, or Scissors next. The
AI would choose what to play, to beat what the opponent is expected to play, weighted by the expected probability for each
possible action.]]></description>
   <content:encoded><![CDATA[<p>Yesterday I had an idea for a simple Rock-Paper-Scissors AI based on Markov chains. The "state" would be what the opponent played
in the last N rounds, and would be used to predict the probability that the opponent would play Rock, Paper, or Scissors next. The
AI would choose what to play, to beat what the opponent is expected to play, weighted by the expected probability for each
possible action.</p>
<p>I quickly wrote it, and went looking online for an AI to test it against. The top result was from "Afiniti":</p>
<p><a class="img" href="https://img.incoherency.co.uk/1761"><img src="https://img.incoherency.co.uk/1761/thumb"></a></p>
<p>You can play against it <a href="https://www.afiniti.com/corporate/rock-paper-scissors">on their website</a>. You'll lose.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1762"><img src="https://img.incoherency.co.uk/1762/thumb"></a></p>
<p>(<b>Update 2018-07-02</b>: Afiniti have now updated their AI, and it now appears totally legit. Good work, Afiniti!
To check whether the version you're playing against is legit, you'll have to a.) check in the "Network" tab in developer tools
that it's making reasonable-looking requests to smartplay.afiniti.com, that don't include the move the player has played,
and b.) make sure that it is actually playing the move that smartplay.afiniti.com tells it to, and c.) for good measure,
play 100 random moves against it and verify that the outcome looks believable. The rest of this article is unchanged.)</p>
<p>The Afiniti AI did <i>extremely</i> well against my Markov model. Suspiciously well. The more rounds I played, the better it
got. These Afiniti guys obviously have some pretty powerful artificial intelligence!</p>
<p>To get an idea of what I was up against, I tried having my program generate completely random moves.
Regardless of how smart your AI is, (and unless you're detecting patterns in the RNG), you can not do better than random chance against
an opponent who is picking moves at random. </p>
<p>To my surprise, the Afiniti AI did very well again. Just as well as last time. The more rounds I played, the better the Afiniti
AI got at predicting the "random" moves that I would choose.</p>
<p>So at this point I wanted to know exactly what they were up to. The text on the page all looks legit, there's nothing
to suggest that the game is a joke or otherwise designed to trick the user, it's presented as a legitimate exercise in artificial
intelligence.</p>
<p>I opened the "Network" tab in the Firefox Developer Tools to see if I could observe the web page communicating remotely with
their AI. There was no network traffic whatsoever, which implies the AI is all javascript. That's good news, because that means
I can find out what it's doing.</p>
<p>Next I downloaded their 1.3 megabytes (!) of minified (!) javascript, and ran it through <a href="http://jsbeautifier.org/">jsbeautifier</a>, to get 41,650 lines of code to look through. This is too much. (It's the code for their entire website, bundled into
one file, not just the Rock-Paper-Scissors AI). I used Firefox Developer Tools again to "inspect element"
on the game's input buttons and found that when you click the scissors button, it calls <tt>checkWinner("Scissors")</tt>. The
<tt>checkWinner</tt> function begins as follows:</p>
<p><pre><code>this.checkWinner = <b>function(t)</b> {
    e.setState({
        computerImage: "handNone",
        inProgress: !0,
        playerImage: "handNone"
    }), setTimeout(function() {
        var n = null,
            o = null,
            r = e.state.gameResult,
            s = ["Rock", "Paper", "Scissors"],
            l = [2, 2, 2];
        <b>l[s.indexOf(t)] = l[s.indexOf(t)] * (Math.floor(e.state.round / 10) + 1);</b>
        var a = <b>e.getCompGuess(s, l);</b></code></pre></p>
<p>It updates the animation states, and then registers a hook to run after a timeout, in which the computer makes its move.
Without even understanding
anything about how the AI works, the parts I've bolded show that:</p>
<p>1.) the array <tt>l</tt> is modified based on the value of <tt>t</tt> (i.e. the player's move).</p>
<p>2.) the array <tt>l</tt> (which may now contain information about the player's move) is passed to <tt>getCompGuess</tt>.</p>
<p>Wat.</p>
<p>At this point there's still a <i>chance</i> that the Afiniti AI is legit. The <tt>getCompGuess</tt> function might completely ignore
its second argument, for example. So let's look at <tt>getCompGuess</tt>:</p>
<p><pre><code>this.getCompGuess = function(e, l) {
    for (var n = 0, o = 0, r = [], s = 0; s < l.length; s++) o += l[s];
    for (; n < e.length;) {
        for (var l = 0; l < l[n]; l++) r[r.length] = e[n];
        n++
    }
    return r[Math.floor(Math.random() * o)]
}</code></pre></p>
<p>Seems... short?</p>
<p>You'll notice that no global state seems to be involved in calculating the
AI's guess, which is odd, given that it is supposed to learn from what the player does. What actually happens is
the array <tt>l</tt> contains a 2 for the actions the human didn't take (e.g. if you played "Rock", <tt>l</tt> contains a 2
for each of "Paper" and "Scissors") and contains some value >= 2 for the action the human did take, with the value increasing as the round
number increases. <tt>getCompGuess</tt> then picks from Rock, Paper, and Scissors at random, weighted by the values in the
<tt>l</tt> array.</p>
<p>This means that as the game goes on, the computer correctly "guesses" what action you <i>took</i> (past tense!) <i>this round</i> with
increasing probability. Because it already knows what action you took. Because the action you took is <i>the only actual input
to the function that is supposed to guess what action you took</i>.</p>
<p>Scam scam scam.</p>
<p>The text on the web page makes this even sneakier: "I correctly predicted you would throw Paper", "SEE HOW THE COMPUTER'S THINKING".</p>
<p>(Incidentally, the text from "SEE HOW THE COMPUTER'S THINKING" is not even consistent with how the AI behaves and is just
generated at random. It might say it's
planning to throw Rock, but then it throws something else. This is because it has no way to know what it is "planning" to
throw until <i>after</i> you have taken your action).</p>
<p>Afiniti's description of their AI is:</p>
<p><blockquote>This rock-paper-scissors game illustrates the <b>basic principles of an adaptive artificial intelligence</b> technology. Like Afiniti, the system <b>learns to identify patterns</b> of a person’s behavior by <b>analysing their decision strategies</b> in order to <b>predict future behavior</b>.<br>
While a computer won’t win all rounds, over time it can <b>learn a person’s behavioral characteristics</b> to perform better than chance. In a similar way, Afiniti improves on the traditional random process of pairing callers with agents by using behaviour to make better pairings.</blockquote></p>
<p>(I've bolded all of the outright lies).</p>
<p>And I hope that the Rock Paper Scissors AI is not really an accurate mirror of the way Afiniti's actual product
"learns to identify patterns".</p>
<p>There is also a "Leaderboard" on the Afiniti rock-paper-scissors page, but I didn't find any code in their javascript that ever sends
user scores off to the server (although I admittedly didn't search all 41,650 lines of it). This along with the handwritten-sounding CSS style names used to import the player pictures implies that the leaderboard is at best
maintained manually, and at worst completely fake.</p>
<p>I contacted Afiniti to ask how their AI works about 24 hours ago, but they've not replied. (<b>Update:</b> they have replied; the Chief Marketing Officer claimed that the AI is using legitimate artificial intelligence, and stopped replying when I linked him to the evidence in this post, but their AI has now been removed!).</p>
<p>While researching other Rock Paper Scissors AIs, I came across <a href="http://www.essentially.net/rsp/">one at essentially.net</a>. Their AI is 100% server-side, so it's impossible
to know whether or not they are cheating. I wrote a script to play 6000 games against their AI, picking moves at random,
and it came out about 1/3 win, 1/3 tie, 1/3 lose, so I am happy to believe that they are above board. Good work, essentially.net.</p>
<p>I also came across <a href="http://www.rpscontest.com/">rpscontest.com</a>, which allows anybody to write an AI in python and
upload it to be entered into the tournament. I found a link to an article on <a href="https://daniel.lawrence.lu/programming/rps/">Rock Paper Scissors algorithms by Daniel Lawrence</a> in one of the AIs I looked at.
He goes into much more detail about how Rock-Paper-Scissors strategies
can work than anything I had come up with. (There's lots of other interesting stuff on his site as well, it's definitely
worth having a look through his <a href="https://daniel.lawrence.lu/programming/">Programming projects</a>).</p>
<p>I did enter <a href="http://www.rpscontest.com/entry/5636800307527680">my Markov Model AI</a> into rpscontest, but it did quite badly.
So far it's played 95 matches, won 47, and is ranked 1300th of 2621. Almost exactly as good as you'd expect if it were
simply picking moves at random...
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/rock-paper-scissors.html</link>
   <guid>http://incoherency.co.uk/blog/stories/rock-paper-scissors.html</guid>
   <pubDate>Fri, 25 May 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Reverse engineering an ebike 3-mode PAS LED panel</title>
   <description><![CDATA[I bought an electric bicycle recently. It is an incredible machine, and I think everyone
should get one. The thing I never liked about cycling is how tired you get going up hills, and the
electric bicycle solves this problem without taking away any of the fun parts of cycling. A truly incredible machine.]]></description>
   <content:encoded><![CDATA[<p>I bought an electric bicycle recently. It is an incredible machine, and I think everyone
should get one. The thing I never liked about cycling is how tired you get going up hills, and the
electric bicycle solves this problem without taking away any of the fun parts of cycling. A truly incredible machine.</p>
<p>This is the bike I bought:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1737"><img src="https://img.incoherency.co.uk/1737/thumb"></a></p>
<p>It's an "eglide folding ebike" and it sells on eBay for around £400 and comes with a ~200 Watt-hour battery,
which is small but adequate. The battery
is easily the most expensive part of the bike.</p>
<p><h3>PAS LED displays</h3></p>
<p>My ebike came with a "3-mode PAS" (pedal assist system) with an LED control panel that looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1738"><img src="https://img.incoherency.co.uk/1738/thumb"></a></p>
<p>(To disassemble it, you need to peel the label sticker off the front and then undo the screws that are hidden underneath. Good
luck getting it back together without horrible crinkles in the label).</p>
<p>You press the power button at top left to turn the system on. It then indicates the battery level
using the upper 4 LEDs. The lower 3 LEDs are used to indicate the 3 different levels of assistance,
which you can cycle through using the "mode" button.</p>
<p>There are a handful of other variations on this type of LED display:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1739"><img src="https://img.incoherency.co.uk/1739/thumb"></a></p>
<p>But I suspect they all work in largely the same way.</p>
<p>I have some ideas for UX improvements, so I intend to implement my own control panel, but in order to
do this I needed to understand the wiring. I couldn't find any documentation online so I worked it out on my
own, and I'm sharing it in case it's useful to anybody else.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1742"><img src="https://img.incoherency.co.uk/1742/thumb"></a></p>
<p>(I soldered the two yellow wires on to facilitate powering it up on the bench).</p>
<p>Circled in green are what appear to be two more spots for pedal assist level LEDs to be placed. I assume the same PCB can be used
for 5-mode PAS systems as well.</p>
<p>The large red circle shows a location for another microswitch, which is used to switch the lights on and off on other variations
of this control panel, and
the smaller red circle shows the LED that I believe indicates whether or not the lights are switched on, which seems to
have been placed on my PCB by mistake - it never comes on and there's no hole in the front label to show it even if it did.</p>
<p>The blue circle shows the location of the wires that were connected to the panel.</p>
<p><h3>Wiring</h3></p>
<p>My control panel had 4 wires connected to it, with the silkscreen labelling them as "VCC", "K", "GND", "TUO". These
are as follows:</p>
<p><ul>
<li><b>GND</b> is ground. Battery negative.</li>
<li><b>VCC</b> is connected to battery positive (it's not voltage-regulated before reaching the control panel, so the voltage drops as the battery runs down).</li>
<li><b>K</b> is used to switch the system on. When K is pulled to VCC, the pedal assist system is enabled, otherwise
the motor doesn't come on (some ebikes have a hand throttle in addition to the pedal assist system; I don't actually know if disconnecting K from VCC disables the motor entirely, or only disables the pedal assist system).</li>
<li><b>TUO</b> is used to set the pedal assist level, in a range of about 2 to 4 volts. I don't yet know whether this is an
analogue signal that can vary continuously, or if the motor controller only supports 3 distinct modes (<b>update:</b> it's 3 discrete levels).</li>
</ul></p>
<p>There are a handful of other wire pads on the PCB, labelled "TX", "DD+", "ZB", "SC". I don't know what these are for. Presumably
at least one of them is for switching the lights on and off. Please <a href="mailto:james@incoherency.co.uk">email me</a> if you
know anything I don't know.</p>
<p><h3>Pedal assist voltages</h3></p>
<p><table border>
<tr><th>Assist level</th><th>Voltage on TUO</th></tr>
<tr><td>LOW</td><td>2v</td></tr>
<tr><td>MED</td><td>3v</td></tr>
<tr><td>HIGH</td><td>4v</td></tr>
</table></p>
<p><b>Update:</b> I found that if "K" is pulled high, the bike is on at least the "LOW" assist level even with no voltage on "TUO". I also didn't observe
any ill effects from connecting "TUO" directly to "VCC". This means in a pinch you can get a working system by just twisting the
VCC and K wires together, and then twisting TUO on to it to switch from LOW to HIGH assist level. I actually rode with VCC, K,
and TUO twisted together (with GND safely taped out of the way), and no control panel at all, for about 20 miles and it all
worked fine. Probably not advisable long-term.</p>
<p><h3>Battery levels</h3></p>
<p>Voltages are approximate, but should be correct to within about half a volt. Note my bike has a 24v battery. Other 
batteries will obviously have different voltage ranges.</p>
<p><table border>
<tr><th>Battery voltage range</th><th>LED pattern</th>
<tr><td>&gt; 25.6</td><td>4 solid LEDs</td></tr>
<tr><td>24.2 - 25.6</td><td>3 solid LEDs</td></tr>
<tr><td>23.6 - 24.2</td><td>2 solid LEDs</td></tr>
<tr><td>22.0 - 23.6</td><td>1 solid LED</td></tr>
<tr><td>&lt; 22.0</td><td>1 flashing LED</td></tr>
</table></p>
<p>I don't know at what voltage the battery management system cuts the power, but I guess it's not too far below 22 volts.</p>
<p><h3>UX improvements</h3></p>
<p>The (minor-ish) issues I have with the control panel are:</p>
<p>1.) It always starts out in "LOW" assist mode regardless of what it was on last time.</p>
<p>When I first switch the bike on I normally want the acceleration to get me up to speed quickly, so I always have to
manually switch it to "HIGH" assist as I set off.</p>
<p>2.) When you press the power button it spends a good 3-4 seconds going through some LED flashing sequence before
actually getting into a state where you can use it.</p>
<p>If I've been cycling along with the system switched off and suddenly
want some quick assistance (for a small hill, or because I had to stop unexpectedly and need to accelerate again), I need
to press the power button, wait 3-4 seconds, and then press the "mode" button twice to switch it to "HIGH" assist mode.</p>
<p>3.) The pedal assist levels are not sufficiently fine-grained.</p>
<p>When trying to ride with another person, it's nice to ride at exactly the same speed. I've found that the "HIGH" assist
mode makes the bike go too fast even with no power input from me, and the "MED" assist mode is too slow unless I pedal
harder than I'd like to. I want more levels in between.</p>
<p>4.) The battery indicator level is not sufficiently fine-grained.</p>
<p>In good conditions I can go a good 45 minutes on "HIGH" assist and still have 4 solid LEDs of battery level.
Then over the course of the next 20 minutes it drops from 4 to 2 LEDs. It would be better to have a more precise
idea of the amount of battery power remaining.</p>
<p>5.) It's impossible to choose the assist level without looking down at the display.</p>
<p>The only way to change the assist level is with the "mode" button, but the mode you move to always depends on the mode
you're already in, which means you need to look at the display to know which mode you'll move in to. Additionally, while the
system is booting up, it does not register presses of the "mode" button, so you need to look at the display to wait for the
thing to be ready before pressing the button will change the mode.</p>
<p>So I'm planning to design a new system using an Arduino Nano, a 160x128 LCD panel, a potentiometer with a thumb-controlled
lever for the
controller inputs, and a 3d-printed case. I'd like to have a tactile click at the start of the potentiometer travel, at which point the "K" wire
is switched on, the display comes on, and the system is enabled. Then I'd like the rest of the potentiometer travel to linearly increase the pedal
assist power, rather than stepping between 3 discrete modes. </p>
<p>In the event that the motor controller only supports 3 different modes, I'll
try to pulse-width modulate between a low mode and a high mode to get the equivalent of a smooth scale. I'd like the system
to "boot up" quickly and be operational almost immediately. I'd like to display the battery power in a vertical bar on the LCD,
like on
a mobile phone. I'd also like to show the speed on the display, by using a hall effect sensor and a magnet
like <a href="https://incoherency.co.uk/blog/stories/scooter-speedo.html">on the scooter speedo driver</a>. Finally, I'd like the case to be relatively small
and elegant, and not obviously a DIY bodge-job, but we'll have to wait and see whether my CAD skills are up to the task.</p>
<p>This should solve all of the problems I identified with the existing control panel.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/ebike-3-mode-pas-led-display-wiring.html</link>
   <guid>http://incoherency.co.uk/blog/stories/ebike-3-mode-pas-led-display-wiring.html</guid>
   <pubDate>Fri, 11 May 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>What would the total computing power of the entire world in 1970 cost today?</title>
   <description><![CDATA[Some dubious mathematics and lots of guesswork. Maybe the conclusion is within a few orders of magnitude of correct...]]></description>
   <content:encoded><![CDATA[<p>Some dubious mathematics and lots of guesswork. Maybe the conclusion is within a few orders of magnitude of correct...</p>
<p><h3>What was the total computing power of the entire world in 1970?</h3></p>
<p>I found a paper by Martin Hilbert and Priscila Lopez that helps to answer this question.
It was published in "Science" magazine (?). "Science" is gatekeeping
access to the content, so you can't actually read it very easily.
Fortunately,
SciHub to the rescue: <a href="http://sci-hub.nu/10.1126/science.1200970">The World's Technological Capacity
to Store, Communicate, and Compute Information</a> (if the link doesn't work, just try one of the many SciHub
mirrors you can find all over the web). Hilariously, "Science" magazine themselves have quite a good article on
<a href="https://www.sciencemag.org/news/2016/04/whos-downloading-pirated-papers-everyone">how great SciHub is</a>.</p>
<p>The part of the paper we are most interested in is figure 5, "World's technological installed capacity to compute information on
general-purpose computers, in MIPS":</p>
<p><a class="img" href="https://img.incoherency.co.uk/1727"><img src="https://img.incoherency.co.uk/1727/thumb"></a></p>
<p><blockquote><b>Assumption:</b> MIPS is a useful way to measure computing power.</blockquote></p>
<p>(Some interesting asides: they estimate that, in 2007, a good 25% of the entire world's computing power was in the form
of videogame consoles. Even more astonishing, in 1986, 41% was pocket calculators! Supercomputers have never been more
than about 0.5%. Abundance of a particular type of device is clearly a much more important multiplier than raw power. Of course,
it's also likely that the world's most superdupercomputers are kept secret...)</p>
<p>The chart gives us data from 1986 to 2007, but there seems to be a clear trend, so let's extrapolate it back in time a bit (note
the scale is logarithmic).</p>
<p><blockquote><b>Assumption:</b> Extrapolating this data backwards in time is valid.</blockquote></p>
<p>The raw data is in "table SA3", which is not included in the paper, but is in the "supporting online material" which is thankfully
<a href="http://science.sciencemag.org/content/sci/suppl/2011/02/08/science.1200970.DC1/Hilbert-SOM.pdf">available
direct from "Science"</a>. All 254 pages of it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1728"><img src="https://img.incoherency.co.uk/1728/thumb"></a></p>
<p>Eh? Only four data points? What about all the other points shown on the chart in figure 5? Never mind. Onwards.</p>
<p>I used <a href="https://planetcalc.com/5992/">PlanetCalc's function approximation tool</a> to calculate an "exponential regression" to fit the 4 data points, where <i>y</i> is the total computing power in MIPS, and <i>x</i> is the year.</p>
<p><i>y = e<sup>0.4868x - 947.4013</sup></i></p>
<p>It has a "correlation coefficient" of 0.994, which sounds good.</p>
<p>Let's try a quick sanity check. The first computer capable of at least 1 MIPS was the <a href="https://en.wikipedia.org/wiki/IBM_7030_Stretch">IBM
7030</a>,
first produced in 1961. Our exponential function places world computing power in 1961 at 834 MIPS. According to
<a href="https://www.historylearningsite.co.uk/inventions-and-discoveries-of-the-twentieth-century/the-personal-computer/">the History
Learning Site</a>, there were 250 computers in total in 1955, and 20,000 in 1965. This might put the number in 1961 at around 3,500 computers (again by exponential regression). If they averaged 0.23 MIPS (834 MIPS divided by 3,500 computers), then we're pretty close.
That sounds believable. At a minimum, 834 MIPS is neither an unrealistic over- nor under-estimate.</p>
<p><blockquote><b>Assumption:</b> The exponential extrapolation I've done is accurate enough to be useful.</blockquote></p>
<p>The exponential regression estimate of world computing power gives us this chart:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1729"><img src="https://img.incoherency.co.uk/1729/thumb"></a><br>
(The raw data is in the table at the end of this post, or calculate it yourself using the formula above).</p>
<p><h3>How much does computing power cost today?</h3></p>
<p>For a representative figure, let's look at renting a CPU on DigitalOcean. The most cost-effective way to rent CPU time on DigitalOcean is with a $5/mo instance. You get 1 CPU at a total cost of $5/mo + VAT = ~&pound;4.35/mo. According to <tt>/proc/cpuinfo</tt> the CPU is an "Intel(R) Xeon(R) CPU E5-2630L v2 @ 2.40GHz". (I checked a handful of DigitalOcean machines I have, and they all listed the same CPU).</p>
<p><tt>/proc/cpuinfo</tt> tells us that this CPU offers 4800 "BogoMIPS". Unfortunately BogoMIPS (as the name suggests) are not
comparable with actual MIPS.</p>
<p>I found <a href="https://www.techspot.com/review/1218-affordable-40-thread-xeon-monster-pc/page5.html">an article by Techspot</a>
which suggests an "Intel Xeon E5-2630 v4" provided around 37,000 MIPS in their 7zip benchmark. I don't know how close a v2 CPU is to a v4, and I don't know
if Techspot's MIPS are comparable to the ones used by Hilbert and Lopez, but we'll just have to assume that they are close enough.</p>
<p><blockquote><b>Assumption:</b> A DigitalOcean CPU gives us about 37,000 MIPS. This will be wrong in the following ways: the 7zip benchmark is not the same type of MIPS; each droplet has access to a shared CPU, not the entire thing.</blockquote></p>
<p><h3>How much would historical computing power cost today?</h3></p>
<p><blockquote><b>Assumption:</b> You can actually rent tens to hundreds of thousands of CPUs on DigitalOcean without them putting their prices up.</blockquote></p>
<p>At &pound;4.35/mo for 37,000 MIPS we get a cost of 12p per month per 1000 MIPS. We already have an estimate of how many MIPS
were available in the entire world for any given year, so let's multiply that by 12p per month per 1000 MIPS to get an
estimate of how much it would cost today to rent those MIPS.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1730"><img src="https://img.incoherency.co.uk/1730/thumb"></a><br>
(The raw data is again available in the table at the end of this post, or calculate it yourself).</p>
<p>Again note that the <i>y</i> axis is a log scale. This makes it easier to differentiate the smaller values, but the true
nature of the data is much more striking with a linear scale:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1731"><img src="https://img.incoherency.co.uk/1731/thumb"></a><br></p>
<p>It's practically free to rent an equivalent to all of the computing power that existed in the entire world at any time before
1960, and in fact you can't even rent a single CPU slow enough to be equivalent to the world's computing power for any time before 1968. That's really quite remarkable. By way of comparison, if you wanted to rent an equivalent of all of the internal combustion
engine power that existed before 1960, it would probably cost the same, within 1 order of magnitude, as what it cost at the time.</p>
<p>Renting historical computing power starts to sting, at &pound;150/mo, if you want to rent all of the power that existed in 1975, and
by 1979 you're spending over &pound;1,000/mo.</p>
<p>If you want to rent all of the computing power that will exist in 2020, that will set you back about &pound;500 billion/mo,
although it should of course be noted that that much computing power won't physically exist in the world until 2020 arrives, and even
then it likely won't all be in the form of DigitalOcean droplets.</p>
<p>In answer to the title: it might cost <b>around &pound;13/mo</b> today to rent an equivalent of all of the computing
power that existed in the entire world in 1970. So there we have it.</p>
<p><h3>Table</h3></p>
<p>Estimates of the entire world's computing power, extrapolated and interpolated, with cost calculated at 12p per month per 1000 MIPS.</p>
<p><table border>
<tr><th>Year</th><th>Computing power (MIPS)</th><th>Cost to rent in 2018 (&pound;/mo)</th></tr>
<tr><td>1950</td><td>6.42E+00</td><td>£0.00</td></tr>
<tr><td>1951</td><td>1.04E+01</td><td>£0.00</td></tr>
<tr><td>1952</td><td>1.70E+01</td><td>£0.00</td></tr>
<tr><td>1953</td><td>2.76E+01</td><td>£0.00</td></tr>
<tr><td>1954</td><td>4.50E+01</td><td>£0.01</td></tr>
<tr><td>1955</td><td>7.32E+01</td><td>£0.01</td></tr>
<tr><td>1956</td><td>1.19E+02</td><td>£0.01</td></tr>
<tr><td>1957</td><td>1.94E+02</td><td>£0.02</td></tr>
<tr><td>1958</td><td>3.15E+02</td><td>£0.04</td></tr>
<tr><td>1959</td><td>5.13E+02</td><td>£0.06</td></tr>
<tr><td>1960</td><td>8.34E+02</td><td>£0.10</td></tr>
<tr><td>1961</td><td>1.36E+03</td><td>£0.16</td></tr>
<tr><td>1962</td><td>2.21E+03</td><td>£0.27</td></tr>
<tr><td>1963</td><td>3.59E+03</td><td>£0.43</td></tr>
<tr><td>1964</td><td>5.85E+03</td><td>£0.70</td></tr>
<tr><td>1965</td><td>9.52E+03</td><td>£1.14</td></tr>
<tr><td>1966</td><td>1.55E+04</td><td>£1.86</td></tr>
<tr><td>1967</td><td>2.52E+04</td><td>£3.02</td></tr>
<tr><td>1968</td><td>4.10E+04</td><td>£4.92</td></tr>
<tr><td>1969</td><td>6.67E+04</td><td>£8.00</td></tr>
<tr><td>1970</td><td>1.09E+05</td><td>£13.00</td></tr>
<tr><td>1971</td><td>1.77E+05</td><td>£21.20</td></tr>
<tr><td>1972</td><td>2.87E+05</td><td>£34.50</td></tr>
<tr><td>1973</td><td>4.67E+05</td><td>£56.10</td></tr>
<tr><td>1974</td><td>7.61E+05</td><td>£91.30</td></tr>
<tr><td>1975</td><td>1.24E+06</td><td>£149</td></tr>
<tr><td>1976</td><td>2.01E+06</td><td>£242</td></tr>
<tr><td>1977</td><td>3.28E+06</td><td>£393</td></tr>
<tr><td>1978</td><td>5.33E+06</td><td>£640</td></tr>
<tr><td>1979</td><td>8.67E+06</td><td>£1,040</td></tr>
<tr><td>1980</td><td>1.41E+07</td><td>£1,690</td></tr>
<tr><td>1981</td><td>2.30E+07</td><td>£2,760</td></tr>
<tr><td>1982</td><td>3.74E+07</td><td>£4,480</td></tr>
<tr><td>1983</td><td>6.08E+07</td><td>£7,300</td></tr>
<tr><td>1984</td><td>9.89E+07</td><td>£11,900</td></tr>
<tr><td>1985</td><td>1.61E+08</td><td>£19,300</td></tr>
<tr><td>1986</td><td>2.62E+08</td><td>£31,400</td></tr>
<tr><td>1987</td><td>4.26E+08</td><td>£51,100</td></tr>
<tr><td>1988</td><td>6.93E+08</td><td>£83,200</td></tr>
<tr><td>1989</td><td>1.13E+09</td><td>£135,000</td></tr>
<tr><td>1990</td><td>1.84E+09</td><td>£220,000</td></tr>
<tr><td>1991</td><td>2.99E+09</td><td>£358,000</td></tr>
<tr><td>1992</td><td>4.86E+09</td><td>£583,000</td></tr>
<tr><td>1993</td><td>7.91E+09</td><td>£949,000</td></tr>
<tr><td>1994</td><td>1.29E+10</td><td>£1,540,000</td></tr>
<tr><td>1995</td><td>2.09E+10</td><td>£2,510,000</td></tr>
<tr><td>1996</td><td>3.41E+10</td><td>£4,090,000</td></tr>
<tr><td>1997</td><td>5.54E+10</td><td>£6,650,000</td></tr>
<tr><td>1998</td><td>9.02E+10</td><td>£10,800,000</td></tr>
<tr><td>1999</td><td>1.47E+11</td><td>£17,600,000</td></tr>
<tr><td>2000</td><td>2.39E+11</td><td>£28,700,000</td></tr>
<tr><td>2001</td><td>3.88E+11</td><td>£46,600,000</td></tr>
<tr><td>2002</td><td>6.32E+11</td><td>£75,900,000</td></tr>
<tr><td>2003</td><td>1.03E+12</td><td>£123,000,000</td></tr>
<tr><td>2004</td><td>1.67E+12</td><td>£201,000,000</td></tr>
<tr><td>2005</td><td>2.72E+12</td><td>£327,000,000</td></tr>
<tr><td>2006</td><td>4.43E+12</td><td>£532,000,000</td></tr>
<tr><td>2007</td><td>7.21E+12</td><td>£865,000,000</td></tr>
<tr><td>2008</td><td>1.17E+13</td><td>£1,410,000,000</td></tr>
<tr><td>2009</td><td>1.91E+13</td><td>£2,290,000,000</td></tr>
<tr><td>2010</td><td>3.11E+13</td><td>£3,730,000,000</td></tr>
<tr><td>2011</td><td>5.05E+13</td><td>£6,060,000,000</td></tr>
<tr><td>2012</td><td>8.22E+13</td><td>£9,870,000,000</td></tr>
<tr><td>2013</td><td>1.34E+14</td><td>£16,100,000,000</td></tr>
<tr><td>2014</td><td>2.18E+14</td><td>£26,100,000,000</td></tr>
<tr><td>2015</td><td>3.54E+14</td><td>£42,500,000,000</td></tr>
<tr><td>2016</td><td>5.76E+14</td><td>£69,100,000,000</td></tr>
<tr><td>2017</td><td>9.38E+14</td><td>£113,000,000,000</td></tr>
<tr><td>2018</td><td>1.53E+15</td><td>£183,000,000,000</td></tr>
<tr><td>2019</td><td>2.48E+15</td><td>£298,000,000,000</td></tr>
<tr><td>2020</td><td>4.04E+15</td><td>£485,000,000,000</td></tr>
</table>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/world-computing-power.html</link>
   <guid>http://incoherency.co.uk/blog/stories/world-computing-power.html</guid>
   <pubDate>Sun, 29 Apr 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How I cracked the Bitcoin keys in Andy Bauch's Lego artwork</title>
   <description><![CDATA[Yesterday I read an article
about a series of art pieces created by Andy Bauch with $10,000 of
cryptocurrency hidden in them. Each of the pieces is assembled out of lego bricks.]]></description>
   <content:encoded><![CDATA[<p>Yesterday I read <a href="https://gizmodo.com/artist-hides-secret-code-to-10-000-worth-of-cryptocurr-1824030024">an article</a>
about a series of art pieces created by <a href="https://andybauch.com/">Andy Bauch</a> with $10,000 of
cryptocurrency hidden in them. Each of the pieces is assembled out of lego bricks.</p>
<p>(Don't read this if you don't want spoilers).</p>
<p><img src="https://img.incoherency.co.uk/1710"><br>
<i>"Bitcoin Initially Valued at $60", by Andy Bauch</i></p>
<p>Each of the images is named after the value of the Bitcoin it was initially funded with, but each one is now worth substantially
more due to the increase in the Bitcoin price.</p>
<p>You can look at the rest of his art <a href="https://andybauch.com/">on his website</a>.</p>
<p>Today I claimed the BTC from 3 of the pieces, totalling ~0.35 BTC (~&pound;2200).
SopaXorzTaker <a href="https://twitter.com/SopaXorzTaker/status/977575503975546880">announced on Twitter</a> that he claimed the BTC from
another two, and the other pieces in the same series have also been claimed, although it's not clear who did it.</p>
<p>After I told Emma that I was working on this, she read up more about the artwork, and eventually found
Andy's <a href="https://newmoney.andybauch.com/">New Money Crypto Prices page</a> which lists the names of the art pieces along with the
amount of BTC in the addresses. It also reveals what the addresses are, which allowed me to find out which pieces
remained unsolved, and therefore which ones to focus my efforts on. This was a big help as time was of the essence, with
other people clearly carrying out the same steps at the same time.</p>
<p>I ended up sweeping the ones that were initially valued at $40, $50, and $60.</p>
<p>Andy's encoding scheme is quite cool. He created private keys by taking the SHA256 of a 30-character base58 string
(a <a href="https://en.bitcoin.it/wiki/Mini_private_key_format">minikey</a>, although I only found this out later - I had
assumed he was just using SHA256 of random alphanumeric strings used like brainwallets).
He then encoded the ASCII byte values of the characters in the minikey as numbers in various bases (the "initial value $20" painting
was base 2, $30 was base 3, $40 base 4, etc.). He then encoded those base-N numbers by using one Lego brick per digit, and one colour
for each possible value. The artwork is then just this encoded private key repeated over and over again.</p>
<p><img src="https://img.incoherency.co.uk/1711"><br>
<i>(I've highlighted one instance of the private key in the $60 image here. The rest of the bricks are just repeating the same pattern.)</i></p>
<p>I manually transcribed the colours of the bricks into a series of letters, double-checking to make sure I got each one right. This
was quite laborious! The $60 image became:</p>
<p><pre><code>BYGRBLBYBLBLBYBRBLGYBYYYBLBYBYBLBYFYBLGYBGRGBGRR
BGFRBLBFBLBYBYFLBLBGBYYBBLYYBGRLBYYFBYGRBYFRBLBF
BGYFBYRRBGRYBGYFBGRRBLGG</code></pre></p>
<p>Where <tt>B</tt> is blue, <tt>Y</tt> is yellow, <tt>G</tt> is grey, <tt>R</tt> is red, <tt>F</tt> is green, <tt>L</tt> is light blue.</p>
<p>There are several possible ways Andy could have mapped the numbers to a Bitcoin key. It could be the raw byte values of the key, it
could be a hex representation of the byte values of the key, it could be the password for a brainwallet/minikey, or any number of other
schemes. Given the
pattern of blue bricks at every 4th position, I surmised that the number was not selected at random from a uniform distribution
of all possible values, which implied most likely the data being represented was ASCII. This assumption turned out to
be correct.</p>
<p>I wrote <a href="https://gist.github.com/jes/af884ad21d5fb2e063c1c00aab08371b">a <i>very</i> dirty Perl script</a> to iterate over every possible mapping of the letters to digits in base 6, and then use
the numbers as byte values, and output the subset of corresponding strings that contain entirely printable ASCII. Here are the possibilities for the $60 image.</p>
<p><pre><code>4mo(y+m'CybdjqmEn*sc/4FqS@aSdz
5mo)y+m'=yhkepm?n*si.5ApRGgRkz
RnoLtVnKht=@FqnimTz?YRjq5d>5@s
SnoMtVnKbtCGApncmTzEXSep4kD4Gs</code></pre></p>
<p>I used bitaddress.org's brain wallet tool to convert these strings into the corresponding bitcoin keys, and used blockchain.info to check
each address to see which ones had ever had any transactions on them. Once I found the one that had some funds (just imagine my excitement!)
I used Electrum to sweep the private key into a wallet under my own control, and the money was mine.</p>
<p><img src="https://img.incoherency.co.uk/1712"></p>
<p>You can see the transaction history for the address <a href="https://blockchain.info/address/1HvEJG5JR84MVpncXcDVBqx65uY5odr6fP">1HvEJG5JR84MVpncXcDVBqx65uY5odr6fP on blockchain.info</a>.</p>
<p>In hindsight, I could have cut down my
manual search space if I knew he was using minikeys: instead of looking for any printable ASCII characters, I could restrict
the character set to only the base58 characters, and additionally the first character must be a capital S.</p>
<p>Having solved the $60 image, I repeated the same steps on the $40 (base 4) and $50 (base 5) images, to great success.</p>
<p>I didn't actually expect to be able to solve any of the artwork, and even if I did solve it I didn't expect to be the first one to do so.
It was all a pleasant surprise, and extremely exciting.</p>
<p>In fact the whole thing was so fun that I intend to copy Andy's idea and make a Lego Bitcoin key art piece of my own. (<b>Update 2018-03-25:</b> I've made a little tool to help generate the grids: <a href="https://incoherency.co.uk/bauch/">Bauch-style Lego Artwork Generator</a>).</p>
<p>Here's what we can reconstruct as a timeline of the solving of the puzzles:</p>
<p><table border>
<tr><th>Time</th><th>Image</th><th>Value</th><th>Address</th><th>Solved by</th></tr>
<tr><td>2018-03-23 21:04</td><td>$70</td><td>0.16 BTC, &pound;1000</td><td><a href="https://blockchain.info/address/12g5BNdmKvHDQXqk37uGEDWDX9AiH7Siuz">12g5BNdmKvHDQXqk37uGEDWDX9AiH7Siuz</a></td><td>Unknown</td></tr>
<tr><td>2018-03-23 23:03</td><td>$90</td><td>0.21 BTC, &pound;1300</td><td><a href="https://blockchain.info/address/16DLhNnN82xAdLKr6DDCnPBmUZ26qcjFhC">16DLhNnN82xAdLKr6DDCnPBmUZ26qcjFhC</a></td><td>Unknown</td></tr>
<tr><td>2018-03-24 12:21</td><td>$20</td><td>0.046 BTC, &pound;290</td><td><a href="https://blockchain.info/address/1NmxAV1ze28U4Uuqg2fH1JTB8NtWKvTyhM">1NmxAV1ze28U4Uuqg2fH1JTB8NtWKvTyhM</a></td><td>SopaXorzTaker</td></tr>
<tr><td>2018-03-24 13:20</td><td>$30</td><td>0.07 BTC, &pound;430</td><td><a href="https://blockchain.info/address/17kdWzib9nnQ3KJJ9LkJyN7nxehb9NuufP">17kdWzib9nnQ3KJJ9LkJyN7nxehb9NuufP</a></td><td>SopaXorzTaker</td></tr>
<tr><td>2018-03-24 14:26</td><td>$80</td><td>0.19 BTC, &pound;1200</td><td><a href="https://blockchain.info/address/1PT9sjy7J9H5271a7GWKeu4C5iDpTFuWTW">1PT9sjy7J9H5271a7GWKeu4C5iDpTFuWTW</a></td><td>Unknown</td></tr>
<tr><td>2018-03-24 14:34</td><td>$60</td><td>0.14 BTC, &pound;870</td><td><a href="https://blockchain.info/address/1HvEJG5JR84MVpncXcDVBqx65uY5odr6fP">1HvEJG5JR84MVpncXcDVBqx65uY5odr6fP</a></td><td>jes</td></tr>
<tr><td>2018-03-24 14:48</td><td>$40</td><td>0.09 BTC, &pound;560</td><td><a href="https://blockchain.info/address/1EbcjT4DxkHQbp5qe6ALrsNDHfGqXozJdc">1EbcjT4DxkHQbp5qe6ALrsNDHfGqXozJdc</a></td><td>jes</td></tr>
<tr><td>2018-03-24 15:47</td><td>$50</td><td>0.11 BTC, &pound;680</td><td><a href="https://blockchain.info/address/1PTsXZrFjFBieS9E4oHT6TcmEXbFDatD9K">1PTsXZrFjFBieS9E4oHT6TcmEXbFDatD9K</a></td><td>jes</td></tr>
</table></p>
<p>Although I've not checked, I assume the $70 and $90 images use the same kind of encoding scheme as all the others, so it's not obvious to me why 
the person (or people) who solved those didn't swipe the others during the following 12 hours.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/andy-bauch-bitcoin-lego.html</link>
   <guid>http://incoherency.co.uk/blog/stories/andy-bauch-bitcoin-lego.html</guid>
   <pubDate>Sat, 24 Mar 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to find out if your data gets stolen (URL Canary)</title>
   <description><![CDATA[In February I started working on a new project called URL
Canary. The premise is that it helps you create custom URLs that you can store next to your
private data (database backups, git repositories, executive inboxes, etc.).
Then, if your data gets compromised and the attacker makes the mistake of visiting your
oh-so-enticingly-named URL, you'll receive an email alert, you'll know your data has been stolen,
and you can take remedial measures.]]></description>
   <content:encoded><![CDATA[<p>In February I started working on <a href="https://urlcanary.com/">a new project called URL
Canary</a>. The premise is that it helps you create custom URLs that you can store next to your
private data (database backups, git repositories, executive inboxes, etc.).
Then, if your data gets compromised and the attacker makes the mistake of visiting your
oh-so-enticingly-named URL, you'll receive an email alert, you'll know your data has been stolen,
and you can take remedial measures.</p>
<p>I was intending to do a better job of most of the text on the site, and add an A/B testing framework, but I
lost interest in it for a few weeks, and then went on holiday. Earlier this week I decided I may
as well post it to Hacker News as-is and see what people think, rather than just let it rot
away. It was surprisingly popular and the <a href="https://news.ycombinator.com/item?id=16619580">comments
on HN</a> were mostly positive. So I now have some renewed interest in the project.</p>
<p>There was some good feedback. Most important was that I need to make it clearer what the
applications of the system are. (I've <a href="https://urlcanary.com/applications">added a page listing
some applications</a>).</p>
<p>In the last 3 days, 242 different email addresses have successfully created a URL Canary, which is a
lot more than I expected.</p>
<p><h2>Bitcoin Canaries</h2></p>
<p>CamTin's <a href="https://news.ycombinator.com/item?id=16620202">comment</a> on Hacker News was particularly interesting:</p>
<p><blockquote>
You might think about embedding bounties in crypto blockchains. For example, create
BTC wallets that can be unlocked using a secret sitting next to (or steganographically
embedded in) the secret you're trying to protect. This gives the person uncovering
the secret an incentive to activate the canary. [...]
</blockquote></p>
<p>The idea there is that instead of giving a URL that the attacker can visit and retrieve something
that might be interesting, at risk of exposing himself, you <i>deliberately</i> give the attacker the private key to a Bitcoin wallet.
As long as the amount of funds in the Bitcoin wallet is chosen in reasonable proportion to the value of data
that would be stolen, the attacker should find it irresistible. You then receive an alert when your Bitcoin has been
spent, and you know the data is compromised.</p>
<p>Choosing the amount of funds "in reasonable proportion" is key, however: an attacker might not bother claiming &pound;50
if he's looking at plaintext passwords for all Skype accounts, but the same amount for a tiny web service that only has 5
users would probably be excessive.</p>
<p>This idea is interesting enough that I plan to implement it myself, and I wouldn't be surprised if others do the same.
Ideally people would be able to choose the amount of money they want to send, pay with a debit card, and receive a private
key to place next to their data, without having to know anything at all about Bitcoin. That flies a bit
too close to "selling people Bitcoin for debit card payments" (and therefore onerous regulatory requirements)
for me to be comfortable, so it'll probably have to be
something worse. There's definitely an interesting idea there, though.</p>
<p><h2>Other projects</h2></p>
<p>I'm not the first to come up with the URL Canary idea. <a href="http://canarytokens.org/generate">canarytokens.org</a>
appears to have been created in 2015. There's also <a href="https://uriteller.io/">Uri Teller</a>, which I
think is just a fantastic name, and appears to date from 2016.</p>
<p>Another related project is <a href="https://breachinsider.com/">Breach Insider</a>
by <a href="https://grh.am/">Graham Stevens</a>. The premise here is a bit different. Instead of
providing a URL which the attacker visits, inadvertently giving himself away, Breach Insider creates
unique email addresses which you can insert into your user accounts table. If a Breach Insider email
address ever receives an email, you get an alert: it means your users table is compromised. Additionally,
if the email address shows up on pastebin, you also get an alert as it means the same thing.</p>
<p>And in case it's not obvious: the name "canary" comes from <a href="https://en.wiktionary.org/wiki/canary_in_a_coal_mine">"canary in a coal
mine"</a>, which is a way to find out if the air in a mine is unsafe to breathe. If the canary suffocates,
you know the air is not safe, and you can take remedial measures hopefully before coming to any
harm.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/stolen-secrets.html</link>
   <guid>http://incoherency.co.uk/blog/stories/stolen-secrets.html</guid>
   <pubDate>Fri, 23 Mar 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>SaaS profit is market inefficiency, and it will end</title>
   <description><![CDATA[I don't think the profitability of "software as a service" businesses is going to last, in the long
term (on a timescale looking at, say, 100 years from now). I wrote before about machine-owned
enterprises competing the profit out of SaaS, but even before that happens, humans ought
to be able to compete most of the profit out of it.]]></description>
   <content:encoded><![CDATA[<p>I don't think the profitability of "software as a service" businesses is going to last, in the long
term (on a timescale looking at, say, 100 years from now). I wrote before about <a href="https://incoherency.co.uk/blog/stories/machine-owned-enterprises.html">machine-owned
enterprises</a> competing the profit out of SaaS, but even before that happens, <i>humans</i> ought
to be able to compete most of the profit out of it.</p>
<p><h2>Why it's a market inefficiency</h2></p>
<p>There are almost no barriers to entry in starting your average SaaS business. There are no licensing
or other onerous regulatory requirements which might help sustain a monopoly, the startup and operating costs
are both extremely low, even negligible (just a VPS and a domain name will do), and the marginal cost
of providing service to an additional user is practically nothing. Despite all this, margins tend to be
huge, implying an excess of demand or a shortage of supply.</p>
<p>If we assume the only barrier to entry is that you need to be able to write the software, then the only thing
standing between any arbitrary SaaS company X and complete irrelevance is that nobody else has yet implemented
a cheaper competitor Y that is good enough to convince X's customers to switch.</p>
<p>In the short term there is more to it, of course. If I'm already a customer of X, I'm probably not going to
switch to new upstart Y just to save a small amount of money. Not until the new upstart has been around for long
enough to prove they're not going to disappear. There is also the problem of marketing: I need some way to
learn that Y exists, and to be confident that Y is actually going to solve the problem at least as well as X.</p>
<p>But in the long term that doesn't matter. In the long term, all existing customers of all existing SaaS services
will be dead, so their biases are irrelevant, and the good businesses ought to spread organically.</p>
<p>I contend that, in the long term, the businesses offering adequate service at the lowest price will "win". I also
contend that, due to the lack of barriers to entry, and the (presumed!) increasing technical literacy in
the world, there will be lots of people eager to eat the lunches of everybody over-charging for basic SaaS products,
and succeeding, and I therefore contend that eventually prices <i>must</i> come down until it's no longer worth competing.</p>
<p>Essentially, SaaS straddles the gap between a post-scarcity supply chain and a rest of the world that is still
used to paying lots of money for things.
But when you're selling "goods" that you can get for free, and that anyone else can get for free as well, you can't
charge very much without driving customers to your competitors.</p>
<p>None of this is to say that you shouldn't start a SaaS project. You should! If you spot a market inefficiency you
should take advantage of it as quickly as possible, before somebody else does.</p>
<p><h2>What can you do to remain competitive?</h2></p>
<p>Apart from the obvious (drop your prices when a credible competitor appears), you can make yourself a less
appealing target for competitors by <a href="http://paulgraham.com/ds.html">doing things that don't scale</a>,
and making those things a core part of your value proposition.</p>
<p>The other option is to just not worry about it and hope that everything goes well for long enough that you'll be
dead before it matters. This is my personal preference.</p>
<p><h2>Why I could be wrong</h2></p>
<p>If the space of all possible SaaS businesses remains roughly where it is today (obviously not the case), I think the arguments above
hold up: prices must come down as markets get more crowded.</p>
<p>But this is arguably the most interesting part:</p>
<p>New inventions are made all the time. If we assume that the space of known inventions is (roughly) a hypersphere in
some many-dimensional space, and that new inventions build on known inventions to expand the hypersphere
slightly in some direction, then the set of all possible new inventions is the "wavefront" of this ever-expanding hyperglobule.
(I first read this concept somewhere else, which I'd like to link to, but unfortunately I can't find it right now).</p>
<p>In the event that the wavefront of all possible new inventions expands at a faster rate than the
software implementation capability of the world grows, then there will always be new possibilities available, and new market entrants
will be better served by entering a new niche than by trying to compete on price in an existing niche. That would be
an excellent outcome.</p>
<p>I wish I knew what was going to happen.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/saas-inefficiency.html</link>
   <guid>http://incoherency.co.uk/blog/stories/saas-inefficiency.html</guid>
   <pubDate>Tue, 20 Mar 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to run SSH and HTTP on the same port</title>
   <description><![CDATA[Last month I ran a small puzzle in which, after having picked up an SSH key in one of the rounds,
a subsequent round involved connecting to a (supposed) web server using an SSH client.
It's quite a neat trick so I thought it deserved sharing.]]></description>
   <content:encoded><![CDATA[<p>Last month I ran a small puzzle in which, after having picked up an SSH key in one of the rounds,
a subsequent round involved connecting to a (supposed) web server using an SSH client.
It's quite a neat trick so I thought it deserved sharing.</p>
<p>The way it works is the sshd and the httpd are actually run on different ports and only listen on the loopback device,
and there's then a tiny proxy sitting in front of them that sniffs the protocol that the client is speaking,
and then connects to the sshd only if it looks like SSH, and the httpd otherwise. That way the only way the client
can speak to the sshd is if he already knows to speak SSH. Anything else will act like a web server as it
will be proxied to the web server.</p>
<p>I'm not sure whether this is the "correct" way to detect an SSH client, but I found that the first 3 bytes
sent by both OpenSSH and PuTTY are always "SSH". So my proxy simply waits for the client to send some data, and if it begins
"SSH" it proxies to the sshd, and otherwise the httpd.</p>
<p>This was surprisingly simple to implement in go, you can <a href="https://gist.github.com/jes/a4a0aa17b25ecd17d27fd10d0b75b220">download the program here</a>.</p>
<p>I very rarely use go, and in fact was initially intending to write this in Perl or C, but goroutines were such a more
natural way to write it than either polling or forking that I couldn't justify <i>not</i> writing it in go!</p>
<p>The main loop waits for connections and then spawns a goroutine to handle that connection. The connection handler
waits for some bytes from the client, and selects the destination for the proxying based on the first 3 bytes
received. Having selected the destination, the connection handler spawns 2 new goroutines and then returns. One
goroutine is a simple loop reading bytes from the client and sending them to the server, and one is the same but
with the endpoints reversed. Nice and simple.</p>
<p>It could probably be extended to be a bit more configurable. Currently all of the config is hardcoded, but it
could easily become a generic proxy to run almost <i>any</i> 2 servers on the same port.</p>
<p>Aside from being a fun puzzle, what could this be useful for?
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/ssh-http.html</link>
   <guid>http://incoherency.co.uk/blog/stories/ssh-http.html</guid>
   <pubDate>Mon, 26 Feb 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>A visual demonstration of the perils of key reuse in a one-time pad</title>
   <description><![CDATA[I was playing with applying one-time pad encryption to images recently, and stumbled across some interesting visualisations
that I want to share.]]></description>
   <content:encoded><![CDATA[<p>I was playing with applying one-time pad encryption to images recently, and stumbled across some interesting visualisations
that I want to share.</p>
<p><h2>One-time pads</h2></p>
<p>From <a href="https://en.wikipedia.org/wiki/One-time_pad">Wikipedia</a>:</p>
<p><blockquote><i>In cryptography, the one-time pad (OTP) is an encryption technique that cannot be cracked, but requires the use of a one-time pre-shared key the same size as, or longer than, the message being sent. In this technique, a plaintext is paired with a random secret key (also referred to as a one-time pad). Then, each bit or character of the plaintext is encrypted by combining it with the corresponding bit or character from the pad using modular addition. If the key is truly random, is at least as long as the plaintext, is never reused in whole or in part, and is kept completely secret, then the resulting ciphertext will be impossible to decrypt or break.</i></blockquote></p>
<p>The operation that combines the plaintext with the key doesn't actually <i>have</i> to be modular addition,
in fact I believe it can be any <a href="https://en.wikipedia.org/wiki/Bijection">bijective</a> function. XOR is often more convenient than modular
addition as it means the decryption operation is the same as encryption.</p>
<p>If we have a message <i>m</i> made up of <i>N</i> elements, and a key <i>k</i> of at least <i>N</i> elements, an encryption operation
&oplus;, and its inverse &ominus;, then we can
produce a ciphertext <i>c</i> of <i>N</i> elements by:</p>
<p><i>c<sub>i</sub> = m<sub>i</sub> &oplus; k<sub>i</sub></i></p>
<p>and retrieve the message from the ciphertext by:</p>
<p><i>m<sub>i</sub> = c<sub>i</sub> &ominus; k<sub>i</sub></i></p>
<p>Simple enough.</p>
<p><h2>One-time pad on images</h2></p>
<p>An image is a 2-dimensional array of pixels, and a pixel is a 3-tuple of numbers representing brightness for red, green, and blue. It's therefore
easy to see how we might apply one-time pad encryption to the pixel values of an image independently of the actual bytes stored in the file format that is
used to represent the image. This is helpful as it allows us to see what is going on visually.</p>
<p>I wrote <a href="https://gist.github.com/jes/dcb6ac7525b507648929c9b0f6de19af">a Perl script to XOR 2 images together</a>.</p>
<p>So here's a picture of <a href="https://en.wikipedia.org/wiki/Lenna">Lenna</a>:</p>
<p><img src="https://img.incoherency.co.uk/1697" style="width:256px"></p>
<p>and here's a randomly-generated key image:</p>
<p><img src="https://img.incoherency.co.uk/1698" style="width:256px"></p>
<p>And we get Lenna XOR key =</p>
<p><img src="https://img.incoherency.co.uk/1699" style="width:256px"></p>
<p>Hopefully you agree that this looks pretty random. Hopefully
you also agree that it is a <i>different</i> random image to the key. Taken alone, this image contains
no information about Lenna at all. It is only by combining it with the key image that we can recover Lenna.</p>
<p><h2>Key reuse</h2></p>
<p>The reason keys mustn't be reused in a one-time pad is that it allows an attacker to learn some information about the underlying plaintexts.</p>
<p>If you encrypt messages <i>m<sub>1</sub></i> and <i>m<sub>2</sub></i> with the same key <i>k</i>, then you get:</p>
<p><i>c<sub>1</sub> = m<sub>1</sub> &oplus; k</i><br>
<i>c<sub>2</sub> = m<sub>2</sub> &oplus; k</i></p>
<p>Individually <i>c<sub>1</sub></i> and <i>c<sub>2</sub></i> are unbreakable, but an attacker who intercepts them both can simply compute:</p>
<p><i>c<sub>1</sub> &ominus; c<sub>2</sub><br>
= (m<sub>1</sub> &oplus; k) &ominus; (m<sub>2</sub> &oplus; k)<br>
= m<sub>1</sub> &ominus; m<sub>2</sub></i></p>
<p>And he's now derived a combination of the 2 <i>plaintexts</i>, with no key material mixed in whatsoever. If either of the plaintexts is
known or easily guessed, the other becomes known immediately. But even in the absence of one or other known plaintext, there is
usable information here.</p>
<p>Take this image of my face, for example:</p>
<p><img src="https://img.incoherency.co.uk/1700" style="width:256px"></p>
<p>After encrypting it with the same key image we used for Lenna above, we get jes XOR key =</p>
<p><img src="https://img.incoherency.co.uk/1701" style="width:256px"></p>
<p>Which looks OK.</p>
<p>But if our ciphertexts were intercepted, the attacker would be able to XOR the 2 images together and retrieve an image
of Lenna XOR jes =</p>
<p><img src="https://img.incoherency.co.uk/1702" style="width:256px"></p>
<p>From which it's easy to identify both Lenna and jes! No bueno.</p>
<p><h2>Weak key generation</h2></p>
<p>I also tried generating a key image where all pixel values between 50 and 150 are fixed at 100, but is otherwise completely random:</p>
<p><img src="https://img.incoherency.co.uk/1703" style="width:256px"></p>
<p>And it looks pretty convincing. I personally can't spot anything obviously wrong with it.</p>
<p>But when we encrypt Lenna using this weak key, we get:</p>
<p><img src="https://img.incoherency.co.uk/1704" style="width:256px"></p>
<p>Which leaks enough of the plaintext information into the ciphertext that we can just about make out Lenna from just <i>one</i> intercepted
ciphertext, and with no extra processing required.</p>
<p><h2>A challenge</h2></p>
<p>If you found this interesting and want some more fun, you might enjoy the following challenge...</p>
<p>Analysts at the Graphical Cryptography Head Quarters, along with their friends at the Notional Security Agency, have intercepted a series of
images that were exchanged between suspected foreign spies.
Baffled by the content of the images, they've called on you as their last hope. Can you crack the code, decipher the images, and save the world?</p>
<p>Download the images at <a href="https://ipfs.io/ipfs/QmPTvvKRGdHWH95imZemLSJYuJWdE1EewWDKjq2bPzjL6G">/ipfs/QmPTvvKRGdHWH95imZemLSJYuJWdE1EewWDKjq2bPzjL6G</a>.</p>
<p>If you solved it, or if you can't solve it and want to know the solution, or if you aren't interested in the challenge and just want to talk one-time pads, please email me: <a href="mailto:james@incoherency.co.uk">james@incoherency.co.uk</a>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/otp-key-reuse.html</link>
   <guid>http://incoherency.co.uk/blog/stories/otp-key-reuse.html</guid>
   <pubDate>Sat, 17 Feb 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I designed a trick chess piece with hidden compartments</title>
   <description><![CDATA[It's quite easy to model a traditional chess piece (apart from a knight) using CAD software. You basically just have to draw a sketch of the outline and revolve
it around its centre. I modelled, and 3d printed, a Queen that includes some hidden compartments for storing small bits of paper, e.g. containing passwords or Bitcoin 
keys.]]></description>
   <content:encoded><![CDATA[<p>It's quite easy to model a traditional chess piece (apart from a knight) using CAD software. You basically just have to draw a sketch of the outline and revolve
it around its centre. I modelled, and 3d printed, a Queen that includes some hidden compartments for storing small bits of paper, e.g. containing passwords or Bitcoin 
keys.</p>
<p>I'm calling it the "Queen's Gambit", because a gambit is both a cunning trick and a chess opening.</p>
<p>(Get it? Opening!)</p>
<p><a class="img" href="https://img.incoherency.co.uk/1695"><img src="https://img.incoherency.co.uk/1695/thumb"></a></p>
<p>If you like, you can watch <a href="https://www.youtube.com/watch?v=tEUXy5hPm6M&t=20s">a short video of me demonstrating it</a> (but there's no talking, and it's not very close-up; the photographs in this post are better).</p>
<p>Here's a cross section of the final model:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1688"><img src="https://img.incoherency.co.uk/1688/thumb"></a></p>
<p>It has 3 threaded connections, and another part that clips into the bottom, secured by a slight taper and the natural ridges from 3d printed layer lines. It is
pushed out by sliding an allen key or similar down from the top, through the hole in the centre of the piece.</p>
<p>I started by creating the different pieces in <a href="https://www.freecadweb.org/">FreeCAD</a>, but with no threads as I'm not good enough
at FreeCAD to model threads.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1690"><img src="https://img.incoherency.co.uk/1690/thumb"></a></p>
<p>The white line is the shape of the body of the piece. The blue circles and green lines are control points for the Bezier curves.</p>
<p>I downloaded <a href="https://www.thingiverse.com/thing:31363">marcaxi's OpenSCAD screw thread library</a> from Thingiverse and used it to generate
all of the threads I needed, and joined them with the FreeCAD-modelled parts.</p>
<p>Here are some photographs of the piece in various stages of disassembly:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1691"><img src="https://img.incoherency.co.uk/1691/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/1692"><img src="https://img.incoherency.co.uk/1692/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/1693"><img src="https://img.incoherency.co.uk/1693/thumb"></a></p>
<p>Thanks to the 3d printing layer lines, it is almost impossible to tell where the openings are. I'm very pleased with how it has turned out.</p>
<p>If you want to print one, you can <a href="https://incoherency.co.uk/interest/queens-gambit.tar.gz">download the STL files</a>.</p>
<p>Please send me some photos if you make one.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/trick-chess-piece.html</link>
   <guid>http://incoherency.co.uk/blog/stories/trick-chess-piece.html</guid>
   <pubDate>Sun, 04 Feb 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Magnetic cubes puzzle: In practice</title>
   <description><![CDATA[I've put together a physical version of the magnetic cubes puzzle and
have spent a good few hours playing with it. (You don't need to have read that post in order for this one to
make sense, but it might help, and it's certainly worth having a look at the table that labels the different cube configurations).
I haven't yet managed to solve it without consulting a computer.]]></description>
   <content:encoded><![CDATA[<p>I've put together a physical version of <a href="https://incoherency.co.uk/blog/stories/magcubes-theory.html">the magnetic cubes puzzle</a> and
have spent a good few hours playing with it. (You don't need to have read that post in order for this one to
make sense, but it might help, and it's certainly worth having a look at the table that labels the different cube configurations).
I haven't yet managed to solve it without consulting a computer.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1673"><img src="https://img.incoherency.co.uk/1673/thumb"></a></p>
<p>(It's sitting in a <a href="https://www.thingiverse.com/thing:327955">Tiny Rubik's Cube Stand</a> designed by <a href="https://www.thingiverse.com/slai98/about">Stephen Lai</a>).</p>
<p><h2>Building it</h2></p>
<p>I recently acquired a new 3D printer. It's an "Anycubic i3 Mega" that I bought directly from China for &pound;289.
The print quality is substantially better than the
<a href="https://incoherency.co.uk/blog/stories/3d-printer.html">cheaper machine I bought last year</a>. I'm very pleased with the Anycubic.</p>
<p>My original plan was to 3D print cubes with hollow spaces just underneath each face, and then drop in magnets mid-print to finish up with
solid cubes with embedded magnets.
Unfortunately, despite the fact that the
nozzle is brass and the heater block is aluminium, the hot end seems to have some steel
in it, and on my first test cube the magnet jumped up out of its hole and stuck to the hot end. So that wasn't going to work.</p>
<p>My next plan was to 3D print cubes with indentations in the faces that I could then superglue magnets in to. I superglued one magnet
into one cube as a test, determined that it would work, and then printed the rest of the cubes (~13 hours of 3D printer time). When I came to glue more magnets in
I found it very difficult to hold the magnets in place without opposing poles in the centre of the cube causing the magnets to flip over, or jump out of place and stick together, before the glue had dried.
I gave this quite a good go but I just couldn't get it to work.</p>
<p>Finally I 3D printed cubes with "stepped" indentations in the faces, and I 3D printed little plugs to fit in the indentations. I glued
a magnet into each plug and then glued the plugs into the faces. This made the magnets easier to handle and less prone to flipping over.
This worked much better. Another benefit of this method is that I can use a different-coloured plastic for the plugs so that I get the
faces coloured for no extra effort.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1671"><img src="https://img.incoherency.co.uk/1671/thumb"></a>
<a class="img" href="https://img.incoherency.co.uk/1672"><img src="https://img.incoherency.co.uk/1672/thumb"></a></p>
<p>Then it's just a case of gluing 162 magnets into 162 plugs, and then gluing 162 plugs into 162 faces.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1669"><img src="https://img.incoherency.co.uk/1669/thumb"></a></p>
<p>Jez suggested sticking the cubes together with velcro instead of magnets. This would be a lot easier to make as you wouldn't have to worry about
unwanted interactions between magnets.</p>
<p><h2>Solving it</h2></p>
<p>I found it very easy to assemble the cubes into a 3x3x3 if you don't care what the outside faces look like. Just pick cubes at random until you find one
that fits, and if you run out of options, remove some cubes at random and try again. I only needed to backtrack 2 or 3 times to find solutions.</p>
<p>With the condition that the outside faces have consistent colours, it is extremely difficult to assemble the cube, and I haven't managed to
do it without looking at a computer-generated solution (of which there are many, many possibilities; I stopped counting them after 100 million,
but I'm interested in placing some bounds on what the exact number could be, please <a href="mailto:james@incoherency.co.uk">email me</a> if you have any insights).</p>
<p>I did come across a few observations that are useful in reasoning about the cubes.</p>
<p><h3>1. Some cubes can only go in certain locations</h3></p>
<p>This seems obvious in hindsight, but is actually quite helpful. For example, the 2 cubes that have 6 green faces can only go in 8 of the 27 possible locations.
And since they both have all-green faces, they can't be touching each other. Similarly, the 2 cubes that have 6 red faces can only go in 8 of the 27 possible
locations, and can't be touching each other.</p>
<p>There are 7 locations in the cube that have 2 adjacent green faces on display, so the cubes that don't have 2 adjacent green faces (if green is South, these are: 6N, 1S, 2So) can't possibly go in those locations, and the same for red (6S, 1N, 2No), on the opposite edges of the cube.</p>
<p><h3>2. You can sometimes disprove solvability of a partial cube without exhaustively searching</h3></p>
<p>Let's say we've assembled the first 2 layers of the cube, and we've got 9 pieces left to place. For sake of argument, let's say we need to have all <i>red</i> faces on top. If we have any cubes that don't have any red faces (6S) then we know immediately that this state is not solvable, and we must backtrack and try again with the 2nd layer.</p>
<p>If we have any cubes that have only 1 red face (1N) then we know that they can be placed in only 4 of the 9 possible locations on the top layer (the red face must face upwards, and the piece can't go in any of the 5 locations that also require a red face to be showing on the side). Furthermore, since the piece must have a green face facing down, it
must be placed on top of a piece from the 2nd layer that has a red face on top. If there are no red faces on top of the 2nd layer in the 4 allowable positions, then we know this state is not solvable, and we must backtrack and try again with the 2nd layer.</p>
<p>You can follow as many of these logical arguments as possible until you either disprove solvability, or find a piece that can only be placed in one location. After placing it, follow similar logic with the remaining pieces, with the added constraint that they must be able to fit next to the pieces that have already been placed.</p>
<p>But we still need a way to place pieces in the lower layers that is better than guessing. I haven't come up with anything for that.</p>
<p><h3>3. Thinking about the faces independently</h3></p>
<p>It can be instructive to think about the faces independently from the cubes to which they're attached. If we can disprove solvability of a set of faces, then
we don't need to care how those faces are arranged into cubes as they won't be solvable regardless.</p>
<p>All of the individual faces end up either visible or non-visible when assembled into a 3x3x3. The non-visible faces are non-visible because they're inside the cube,
and adjacent to another non-visible face, of the opposing polarity.
That means exactly half of the non-visible faces are red, and exactly half are green, otherwise it would not be solvable. So we need to have at least 6*9=54 red and 54 green faces just in order to be able to assemble the cubes into a 3x3x3.</p>
<p>This doesn't actually help us with the cube set I've made, since there are exactly 81 red and 81 green faces, but it helps to rule out
certain outer-face patterns as impossible.</p>
<p><h2>A solution</h2></p>
<p>Here's one of the solutions I generated.</p>
<p>Red is North and green is South. The outside cells
are labelled with just a colour to show what colour should be facing in that direction (green left and top, red right and bottom), and the cells representing individual cubes are labelled with the
colour that should be facing upwards. The bottom layer is given first (and must have green faces facing down), then the middle layer is given, and then the top layer.</p>
<p><table border></p>
<p><tr><td></td><td></td><td style="background:lightgreen"></td><td style="background:lightgreen"></td><td style="background:lightgreen"></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td style="background:lightgreen"></td><td></td><td style="background:lightgreen">6S</td><td style="background:lightgreen">1N</td><td style="background:lightgreen">2No</td><td></td><td style="background:pink"></td></tr>
<tr><td style="background:lightgreen"></td><td></td><td style="background:pink">3C</td><td style="background:pink">3R</td><td style="background:lightgreen">3C</td><td></td><td style="background:pink"></td></tr>
<tr><td style="background:lightgreen"></td><td></td><td style="background:lightgreen">1N</td><td style="background:lightgreen">2So</td><td style="background:lightgreen">3C</td><td></td><td style="background:pink"</td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td style="background:pink"></td><td style="background:pink"></td><td style="background:pink"></td><td></td><td></td></tr>
</table></p>
<p><table border>
<tr><td></td><td></td><td style="background:lightgreen"></td><td style="background:lightgreen"></td><td style="background:lightgreen"></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td style="background:lightgreen"></td><td></td><td style="background:pink">2No</td><td style="background:lightgreen">2Sa</td><td style="background:pink">2Sa</td><td></td><td style="background:pink"></td></tr>
<tr><td style="background:lightgreen"></td><td></td><td style="background:lightgreen">2Na</td><td style="background:lightgreen">6S</td><td style="background:pink">2So</td><td></td><td style="background:pink"></td></tr>
<tr><td style="background:lightgreen"></td><td></td><td style="background:pink">2So</td><td style="background:lightgreen">2Sa</td><td style="background:pink">6N</td><td></td><td style="background:pink"</td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td style="background:pink"></td><td style="background:pink"></td><td style="background:pink"></td><td></td><td></td></tr>
</table></p>
<p><table border>
<tr><td></td><td></td><td style="background:lightgreen"></td><td style="background:lightgreen"></td><td style="background:lightgreen"></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td style="background:lightgreen"></td><td></td><td style="background:pink">1N</td><td style="background:pink">1S</td><td style="background:pink">2Na</td><td></td><td style="background:pink"></td></tr>
<tr><td style="background:lightgreen"></td><td></td><td style="background:pink">1S</td><td style="background:pink">2No</td><td style="background:pink">1S</td><td></td><td style="background:pink"></td></tr>
<tr><td style="background:lightgreen"></td><td></td><td style="background:pink">2Na</td><td style="background:pink">6N</td><td style="background:pink">3R</td><td></td><td style="background:pink"</td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td style="background:pink"></td><td style="background:pink"></td><td style="background:pink"></td><td></td><td></td></tr>
</table></p>
<p>Probably doesn't make much sense on its own, but if you have a set of cubes in front of you, it'll help. I swear.</p>
<p>For example, consider the 3C on the left of the middle row of the first layer. We know it needs to have a green face facing down because it's the first layer. We know it needs to have a green face facing left because all of the left-most faces have to be green. We know it needs to have a red face facing up because the cell is shaded red. That's enough information to know how to place the cube. I think some of the squares are actually ambiguous, but they become non-ambiguous if you just skip them and place the surrounding cubes first.</p>
<p>Anyway, I think that's about all I've got to say about the cubes for now, aside from the answers to the questions from the end of the last post. If you make
a set of cubes or have any insights into how they might be solved please get in touch.</p>
<p><h2>Exercise solutions</h2></p>
<p><h3>1. Is it possible to choose a cube set that is impossible to assemble into a 3x3x3 cube?</h3></p>
<p>Yes. A trivial example is 27 6N cubes. You can't assemble 2 6N cubes together in any orientation, so it's obviously impossible to assemble 27 of them together.
More interestingly (as discussed above), any set of cubes which has fewer than 54 red or fewer than 54 green faces can not be assembled into a 3x3x3.</p>
<p><h3>2. Is it possible to assemble the cube set given above (2x 6N, 2x 6S, 2x 3R, 3 each of the rest) into a 3x3x3 cube of cubes that has the same colour on every outside face?</h3></p>
<p>No. We always need to have 54 red and 54 green faces in the non-visible parts of the cube. If we want all of the outer faces to be red, we need all 54
of the outer faces to be red as well, for 108 red faces in total. Since our cube set has only 81 red faces and 81 green faces, it is impossible to assemble into a 3x3x3
that has the same colour on every outside face.</p>
<p><h3>3. Is it possible to choose a cube set that can be arranged in to both a checkerboard pattern and a consistent-faces pattern?</h3></p>
<p>No. Consider the checkerboard image I mentioned last time:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1678"><img src="https://img.incoherency.co.uk/1678/thumb"></a></p>
<p>You'll note that the edges of the cube don't seem to follow the checkerboard pattern as applied to individual faces. The reason is that on each of the corners
we find a square where we can place neither red nor green without breaking the pattern:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1681"><img src="https://img.incoherency.co.uk/1681/thumb"></a></p>
<p>Therefore the only checkerboard pattern that can actually make sense on a cube is a checkerboard of <i>cubes</i>, rather than <i>faces</i>.</p>
<p>You'll also note that each face has 5 red faces showing and only 4 green faces showing, for a total of 6*5=30 red faces and 6*4=24 green faces. We know that both a checkerboard pattern and a consistent-faces pattern have exactly 54 red and 54 green squares in the non-visible part of the cubes. So we need to decide if it is possible to create a consistent-faces pattern that uses 30 red faces and 24 green faces, and the answer is no.</p>
<p>If we want 3 red 3x3 faces and 3 green 3x3 faces, we need 27 of red and 27 of green, which isn't enough reds. If we make a concession for extra red faces and go for 4 red and 2 green sides, we need 36 red and 18 green faces, which is too many reds and not enough greens.</p>
<p>Therefore it is not possible for any cube set that can form a checkerboard pattern to also form any consistent-faces pattern.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/magcubes-practice.html</link>
   <guid>http://incoherency.co.uk/blog/stories/magcubes-practice.html</guid>
   <pubDate>Mon, 22 Jan 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Magnetic cubes puzzle: In theory</title>
   <description><![CDATA[I had an idea for a puzzle. Imagine 27 small cubes. Put a magnet on each face of each cube, with variation as to whether North or South is facing outwards.
Now try to assemble the cubes into a 3x3x3 "cube of cubes".]]></description>
   <content:encoded><![CDATA[<p>I had an idea for a puzzle. Imagine 27 small cubes. Put a magnet on each face of each cube, with variation as to whether North or South is facing outwards.
Now try to assemble the cubes into a 3x3x3 "cube of cubes".</p>
<p>To make the puzzle a little more tractable, we can colour the faces of the 27 individual cubes to tell whether they are North or South. E.g. red is North and green is South.</p>
<p><img src="https://img.incoherency.co.uk/1676"></p>
<p>(<b>Update 2018-01-23:</b> Thanks Jez for supplying neater artwork than I managed on my own, all of these diagrams are his).</p>
<p>And to make it a bit more interesting we can
stipulate that each of the 3x3 outer faces of the 3x3x3 cube of cubes must have a consistent colour.</p>
<p><img src="https://img.incoherency.co.uk/1677"></p>
<p>Or perhaps a checkerboard pattern.</p>
<p><img src="https://img.incoherency.co.uk/1678"></p>
<p><h2>Cube Types</h2></p>
<p>Since the polarity of the magnets is fixed, not all cubes are equivalent. For example,
a cube that has 2 faces with North poles facing outwards is clearly different from a cube that has 3 faces with North poles facing outwards.</p>
<p>A cube has 6 faces, and each face is in 1 of 2 states (North or South), so there are 2<sup>6</sup>=64 different configurations of a cube. However,
many of these configurations are rotational symmetries of one another. For example, the 64 figure includes 6 different cubes that have 1 North face and 5 South
faces, but in real life these are equivalent as you can simply rotate the cube.</p>
<p>It turns out there are only 10 distinct configurations of the cube that are not rotational symmetries of one another, which I've labelled as follows:</p>
<p><table border>
<tr><th>Label</th><th>Description</th></tr>
<tr><td>6N</td><td>6 North faces</td></tr>
<tr><td>6S</td><td>6 South faces</td></tr>
<tr><td>1N</td><td>1 North face, 5 South faces</th></tr>
<tr><td>1S</td><td>1 South face, 5 North faces</td></tr>
<tr><td>3R</td><td>3 North faces, 3 South faces. All of the North faces are adjacent to each other, and all of the South faces are adjacent to each other</td></tr>
<tr><td>3C</td><td>3 North faces, 3 South faces. Not all of the faces of the same type are adjacent</td></tr>
<tr><td>2Na</td><td>2 North faces, 4 South faces. The North faces are adjacent to each other</td></tr>
<tr><td>2No</td><td>2 North faces, 4 South faces. The North faces are opposite each other</td></tr>
<tr><td>2Sa</td><td>4 North faces, 2 South faces. The South faces are adjacent to each other</td></tr>
<tr><td>2So</td><td>4 North faces, 2 South faces. The South faces are opposite each other</td></tr>
</table></p>
<p>Mostly self-explanatory, but the difference between 3R and 3C deserves a diagram. The R and C come from "3 in a ring" and "3 in a cup". Not that that makes any more sense.</p>
<p>Here's 3R:</p>
<p><img src="https://img.incoherency.co.uk/1680"></p>
<p>and here's 3C:</p>
<p><img src="https://img.incoherency.co.uk/1679"></p>
<p>Hopefully you can visualise what that would be like in a 3D cube. Ideally I would have made an animation of a 3D cube rotating, showing all 6 sides. You'll
notice that in 3R all of the red faces touch each other and all of the green faces touch each other, whereas in 3C only 1 red face touches both of the other 2, and only
1 green face touches both of the other 2.</p>
<p><h2>Cube Sets</h2></p>
<p>We need to make sure to pick a set of cubes that can actually fit together to form a 3x3x3. We can trivially do this by choosing
27 3R cubes, and then assemble every single cube in the same orientation, with the South faces pointing one way and the North faces pointing the other way, but that
doesn't make for a very interesting puzzle.</p>
<p>Coming up with a good cube set is a puzzle all of its own. Ideally we'd have near-equal numbers of each cube type.</p>
<p>I wrote <a href="https://gist.github.com/jes/cd42c4ee8314436e6bb2fb0f4b5dcd8f">a C program</a> to search for sets of cubes that can form a 3x3x3 cube with consistent colours on the faces, and I eventually found this solution, which is as close to "near-equal numbers of each cube type" as it is possible to get:</p>
<p>2x 6N<br>
2x 6S<br>
2x 3R<br>
3x all the rest</p>
<p>Happily, this cube set can be assembled into both the 3C and 3R configurations of the consistent-faces pattern. (I checked with the C program). That's sure to present endless hours of fun...</p>
<p>I intend to 3D print a physical version of this puzzle (now done, <a href="https://incoherency.co.uk/blog/stories/magcubes-practice.html">read about it here</a>). I suspect it might be extremely
difficult to solve. It doesn't <i>sound</i> too hard (it's just 27 cubes, how hard could it be?),
but I've been running an exhaustive search for about a day and have so far found 55
million different <i>solutions</i> for assembling the cube set specified above into a 3x3x3 cube with consistent face colours. I have no idea
how many solutions are left to find.
The number of ways to combine these 27 cubes is almost unimaginably large.</p>
<p>A 3x3x3 cube has 27! permutations, which is already about
10<sup>28</sup>. On top of that, each cube can be rotated into 24 different orientations. So even after you've picked one of the 10<sup>28</sup> ways to
arrange the cubes in space, you have 24<sup>27</sup> = 1.8*10<sup>37</sup> different ways to actually assemble it, before you find out whether all of your
North and South poles line up. Which they probably don't. (Although, again, rotational symmetry cuts down on this number quite substantially).</p>
<p>I don't even know if it'll be <i>possible</i> for a human to solve it without looking at an answer generated by a computer.</p>
<p>We'll find out how hard it really is after I've managed to assemble a real-life version of the puzzle. Incidentally, I have found that to be harder than it sounds as well.
Magnets tend to stick together in places you don't want them to stick together, and repel in places you don't want them to repel.</p>
<p><h2>Exercises for the reader</h2></p>
<p>Some things to think about until next time:</p>
<p><ol>
<li>Is it possible to choose a cube set that is impossible to assemble into a 3x3x3 cube?</li>
<li>Is it possible to assemble the cube set given above (2x 6N, 2x 6S, 2x 3R, 3 each of the rest) into a 3x3x3 cube of cubes that has the same colour on every outside face?</li>
<li>Is it possible to choose a cube set that can be arranged in to both a checkerboard pattern and a consistent-faces pattern?</li>
</ol></p>
<p>Answers available <a href="https://incoherency.co.uk/blog/stories/magcubes-practice.html">in the follow-up article</a>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/magcubes-theory.html</link>
   <guid>http://incoherency.co.uk/blog/stories/magcubes-theory.html</guid>
   <pubDate>Sat, 20 Jan 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to get your Bitcoins out of Xapo without running their app on your phone</title>
   <description><![CDATA[Xapo is a company that offered a Bitcoin Visa debit card. You'd top up your account
with Bitcoins, and you can then spend them, using the card, anywhere that takes Visa payments. This is super convenient
for anyone who earns income in Bitcoin.]]></description>
   <content:encoded><![CDATA[<p><a href="https://xapo.com/">Xapo</a> is a company that offered a Bitcoin Visa debit card. You'd top up your account
with Bitcoins, and you can then spend them, using the card, anywhere that takes Visa payments. This is super convenient
for anyone who earns income in Bitcoin.</p>
<p>Unfortunately, on the 5th of January, and with no notice, <a href="https://www.reddit.com/r/Bitcoin/comments/7oabzl/all_bitcoin_visa_debit_cards_are_now_cancelled/">all Bitcoin Visa cards were cancelled</a>. WaveCrest Holdings is the company that issued these cards, Xapo is just a customer of WaveCrest. Visa
had instructed WaveCrest that they must immediately cancel all of their cryptocurrency-related cards. Bummer.</p>
<p>With no remaining use for the Bitcoin that was in my Xapo wallet, I wanted to withdraw it. I logged into their website
and tried to withdraw it but was told that I must approve the withdrawal using the Xapo app.</p>
<p>When I signed up for Xapo there was no Xapo app. I was never made aware that the only way I'd be able to withdraw my money is by running
their proprietary code on my phone. I never agreed to run it, and have never used it. I run
<a href="https://copperhead.co/android/">CopperheadOS</a> on my phone, which uses <a href="https://f-droid.org/">F-Droid</a> as a software repository
 instead of Google Play, so I don't even
know how I'd install their app (probably "allow installation from untrusted sources" and go and work out how to download the APK
from the Google Play website?). At any rate, I refuse to run non-free code on my phone, so that option is out.</p>
<p>I emailed Xapo support 10 days ago to insist that they allow me to withdraw my money, but still haven't heard back.</p>
<p>So today I tried to do it their way. I got hold of an Android phone that was already plugged into the closed-source Google ecosystem,
and installed the Xapo app on it. The first thing the app asks for is your phone number. I wasn't sure whether I should put
<i>my</i> phone number, or the phone number of the phone. I tried my phone number first and received a verification code via SMS on
my own phone, but had no way to type it into the app, as it was expecting to receive the SMS itself. Next I tried the phone number
of the Android phone, and the app took me to the next screen, where it asked for my email address. After I entered my email address
I was told that it was unfortunately already registered with a different phone number.</p>
<p>My next trick was going to be to swap the SIM cards between my phone and the Android phone, but <a href="https://curbedambition.com/">James</a>
suggested manually forwarding the verification code from my phone to the Android phone. So I input my phone number,
received the SMS on my phone, and forwarded it to the Android phone. It worked! The app accepted it and I was then able to log in using my email address.</p>
<p>The app then insists on taking a photograph of your face which it sends off to the mothership. I'm not 100% sure why it does this, and not sure
if it checks it against anything, or if it even checks that there is a face in the photograph. I gave it a photograph of myself, anyway.</p>
<p>I clicked around the interface and found the part where you can send out your money by scanning a Bitcoin address QR code. I tried this a few times,
but every time I scanned the QR code, the app just took me back to its overview screen instead of letting me send any money. I also tried manually typing
in the Bitcoin address instead of scanning a QR code, and the app had the same behaviour.</p>
<p>What I had to do was log in to the Xapo website using my laptop, try to withdraw the Bitcoin like I had tried to the first time, and then a notification pops up in the
app, which I can use to "approve" the withdrawal. I did this, and a few minutes later the payment showed up on the Bitcoin network, and it is now confirmed.</p>
<p>So now I've got my Bitcoins back, and I haven't had to taint my real phone with code I don't trust. I consider that a decent result.
It's a good reminder though: if you don't control the Bitcoin keys, you don't control the Bitcoins.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/get-coins-out-of-xapo.html</link>
   <guid>http://incoherency.co.uk/blog/stories/get-coins-out-of-xapo.html</guid>
   <pubDate>Mon, 15 Jan 2018 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Knives: they cut, and they don't ask no fucking questions. Yet.</title>
   <description><![CDATA[I recently watched Captain Disillusion's video Miss Ping Debunk
in which he explains how an old knife-throwing video was made, and why, and by whom. It's a good video. It also has a joke
advert in the middle:]]></description>
   <content:encoded><![CDATA[<p>I recently watched Captain Disillusion's video <a href="https://www.youtube.com/watch?v=W8sGTh7ZpoY">Miss Ping Debunk</a>
in which he explains how an old knife-throwing video was made, and why, and by whom. It's a good video. It also has a joke
advert in the middle:</p>
<p><blockquote>This week's Captain Disillusion is brought to you by <i>knives</i>... They cut, and they don't ask no fucking questions.</blockquote></p>
<p>I enjoyed this line, but I wonder how long it'll remain true.</p>
<p>We already have laws in the UK (and, I assume, in most other "civilised" countries) about <a href="https://www.gov.uk/buying-carrying-knives">how long a knife can be</a> before you're not allowed
to have it on your person without a convincing excuse.</p>
<p>We already have technology available that can <a href="https://www.youtube.com/watch?v=eiYoBbEZwlk">retract a tablesaw blade</a> as soon as it touches skin.</p>
<p>I'm sure it wouldn't take <i>too</i> much imagination to build a "smart knife" that automatically retracts the blade
as soon as it touches skin. With electronics getting smaller and cheaper every day, it wouldn't have to be substantially large
or expensive.</p>
<p>According to the Washington Post there were <a href="https://www.washingtonpost.com/national/health-science/knife-injuries-and-other-kitchen-mishaps-afflict-both-top-chefs-and-everyday-cooks/2013/01/07/92e191f8-4af0-11e2-b709-667035ff9029_story.html?utm_term=.b933759e0077">almost 330,000 hospital visits in the US in 2011</a> caused
by knife accidents. These could almost all be avoided in a future where the users had paid a little extra and opted for smart knives.</p>
<p>But why stop there? After smart knives became widely-available, it wouldn't take much to amend the existing legislation to outlaw the sale of legacy
knives completely!</p>
<p>There's a very clear trend towards tools and systems that are not under the control of their users.
Printers <a href="https://www.pcworld.com/article/229647/counterfeit_money_on_color_laser_printers.html">won't print anything that looks like money</a>.
Quadcopters <a href="https://www.dji.com/newsroom/news/dji-fly-safe-system">won't fly near airports</a>.
Cars can <a href="http://www.nydailynews.com/news/crime/fla-woman-car-calls-police-alleged-hit-and-run-article-1.2456939">automatically call the police on you</a> if they think you've done something wrong.
Mobile phones can be used remotely <a href="https://en.wikipedia.org/wiki/Cellphone_surveillance">to listen to your in-person conversations</a>.</p>
<p>Having machines help make decisions for us is great, but if we're not careful we'll end up in a world where
the machines are telling us what to do, and not the other way around.</p>
<p><blockquote>I'm sorry, Dave, I'm afraid I can't do that</blockquote></p>
<p>Maybe Richard Stallman was right all along.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/knives.html</link>
   <guid>http://incoherency.co.uk/blog/stories/knives.html</guid>
   <pubDate>Wed, 27 Dec 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to control a digital speedometer</title>
   <description><![CDATA[As part of my YX140 scooter project
(now finished)
I discovered that the scooter's speedometer is controlled digitally. There was a sensor in the original engine
which generated pulses to signal the speed of rotation of the gearbox output shaft.  
The new engine has no such sensor, so I had to do a little electronics to make the speedo work.]]></description>
   <content:encoded><![CDATA[<p>As part of my <a href="https://incoherency.co.uk/blog/stories/innova-yx140.html">YX140 scooter project</a>
(<a href="https://img.incoherency.co.uk/1632">now finished</a>)
I discovered that the scooter's speedometer is controlled digitally. There was a sensor in the original engine
which generated pulses to signal the speed of rotation of the gearbox output shaft.  
The new engine has no such sensor, so I had to do a little electronics to make the speedo work.</p>
<p>The old speedo sensor has 3 wires leading to it. One is tied to ground, one is +7v,
and one is the output signal. I watched <a href="https://www.youtube.com/watch?v=9DirjbUJKXE">this YouTube
video</a> to find out how the sensor works. In short, it pulls the signal wire to ground
every time the sensor registers the passage of a tooth on the gear it is sensing, and leaves the wire floating
when no tooth is passing.</p>
<p>So all I need to do is measure the speed of the scooter in some way, and then pull the signal wire to ground
at some frequency to make the speedo register the correct speed.</p>
<p>To measure the speed, I opted to place
 a magnet on the front wheel, with a hall effect sensor to detect the passage of the magnet.
This is a much lower-frequency signal than the one given by the gearbox sensor, but at speeds above walking pace
it's good enough to work perfectly well.</p>
<p>To give the corresponding signal on the speedo signal wire, I wrote
<a href="https://gist.github.com/jes/6f7550545a094f1517f9b96ee6889027">a short Arduino program</a> that uses the
ATmega's "Timer1" to generate a PWM signal that then controls a transistor to connect and disconnect the signal wire
to/from ground. I wanted to use an ATtiny but I couldn't work out how to drive any of the ATtiny's timers at a high enough
precision to cover the full range of speeds that I'd need to display. It's probably possible, it's just easier to use
an ATmega.</p>
<p>Here's the rather messy circuit I made on a piece of perfboard:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1616"><img src="https://img.incoherency.co.uk/1616/thumb"></a></p>
<p>The green connector plugs into the existing speedo sensor connector on the scooter, and the black cable leads to
a connector for the hall effect sensor I need to place on the front wheel.</p>
<p>The circuit is just a 5V voltage regulator, a filtering capacitor (probably unnecessary, but can't hurt), an ATmega328
microcontroller (running Arduino etc. <a href="https://www.arduino.cc/en/Tutorial/ArduinoToBreadboard">as described here</a>), a transistor for the output signal, an LED for debugging, and
a convenient programming header Just In Case&#8482; I didn't get the software right first time. The board looks more complicated
than it is because I'm bad at layout.</p>
<p>It's in a 3d-printed case, and I filled the case with black polyurethane resin to keep everything nice and secure against vibration and water ingress:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1617"><img src="https://img.incoherency.co.uk/1617/thumb"></a></p>
<p>Looking good, don't you think? What I hadn't considered is that the programming header is not watertight, and I inadvertently filled it up with resin! Let's hope I never have
to reprogram the ATmega...</p>
<p>I 3d printed some parts to hold the magnet and the hall effect sensor, and attached them to the front wheel:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1627"><img src="https://img.incoherency.co.uk/1627/thumb"></a></p>
<p>(At some point I'd like to replace the magnet holder with one that doesn't need to be spaced away from the hub with washers,
and I'd like to replace the hall effect sensor holder with something that can stay in place with fewer cable ties. But these
work OK for now.)</p>
<p>The LED on the circuit board lights every time the sensor detects the magnet. This makes it easy to position the sensor and the magnet without
having to spin the wheel fast enough to register a speed on the display.</p>
<p>Having aligned the sensor and the magnet, I set off for a test ride and was disappointed to find that the sensor only intermittently
detected the magnet, causing the speedo display to wave around erratically. My
initial attempt at the software tried to "auto-range" the analogue signal from the sensor, but that turned out
to be unreliable when the magnet was moving too fast. That meant I had to modify the program, and that meant I had to use the
programming header. The one that I'd filled with resin.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1626"><img src="https://img.incoherency.co.uk/1626/thumb"></a></p>
<p>I spent an hour or so scraping away little bits of plastic until I managed to expose some small pieces of conductor
in the programming header. I then soldered some short orange wires on to the conductors and was able to successfully upload an updated
program to the ATmega! I simply replaced the elaborate auto-ranging code
with a fixed threshold, and that worked much better. The speedo now works nice and smoothly, and apart from the rather attractive
green mass attached to the front wheel, you'd never know it wasn't working the way Honda intended.</p>
<p>I debated removing the orange wires from the programming pins, but in the end I just wrapped them in insulating tape and left them on.
They might be useful one day.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/scooter-speedo.html</link>
   <guid>http://incoherency.co.uk/blog/stories/scooter-speedo.html</guid>
   <pubDate>Tue, 12 Dec 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Is mega.co.nz censored by every major search engine?</title>
   <description><![CDATA[I was watching Vice's video on Kim Dotcom
today, and ended up typing "mega" into DuckDuckGo to see what it came up with.]]></description>
   <content:encoded><![CDATA[<p>I was watching <a href="https://www.youtube.com/watch?v=gMxhIfG0MpY">Vice's video on Kim Dotcom</a>
today, and ended up typing "mega" into DuckDuckGo to see what it came up with.</p>
<p><a href="https://en.wikipedia.org/wiki/Mega_(service)">Mega</a> is a "secure cloud storage" service with end-to-end encryption. It was initially launched
by Kim Dotcom after his previous service, <a href="https://en.wikipedia.org/wiki/Megaupload.com">Megaupload</a>, was shut down by the US
government. The <a href="https://en.wikipedia.org/wiki/Mega_(service)#History">History of Mega</a> is quite interesting: Kim stepped down
as director, and supposedly a Chinese investor performed a hostile takeover, then the New Zealand government seized the Chinese investor's
shares, and now the New Zealand government controls the site and Kim doesn't trust it any more.</p>
<p>But this isn't about that. This is about what I <i>didn't</i> find when searching for "mega" in various search engines.</p>
<p>DuckDuckGo:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1640"><img src="https://img.incoherency.co.uk/1640/thumb"></a></p>
<p>Google:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1641"><img src="https://img.incoherency.co.uk/1641/thumb"></a></p>
<p>Bing:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1642"><img src="https://img.incoherency.co.uk/1642/thumb"></a></p>
<p>Ask.com:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1643"><img src="https://img.incoherency.co.uk/1643/thumb"></a></p>
<p>None of them actually came up with the Mega website! Google has a link to the Wikipedia article on Mega, and
all except Ask.com have tangentially-related links like the Android app and the Chrome extension. But none of
them link to the actual website.</p>
<p>Even typing in "mega.co.nz" doesn't come up with a link to the Mega homepage, it's all other websites and other
URLs on the Mega website.</p>
<p>This leads me to believe that the major Western search engines are actively filtering the mega.co.nz homepage out of their results.</p>
<p>(DuckDuckGo probably isn't complicit in this, it just repackages Bing results but with less surveillance. But using
DuckDuckGo still isn't enough to get uncensored search results).</p>
<p>In contrast to all of the above, both <a href="https://www.yandex.com/">Yandex</a> and <a href="http://www.baidu.com/">Baidu</a>
come up with mega.co.nz on the first page of results:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1645"><img src="https://img.incoherency.co.uk/1645/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/1644"><img src="https://img.incoherency.co.uk/1644/thumb"></a></p>
<p>So the answer to the question is: No, mega.co.nz is not censored by every major search engine. It's only
censored by every major <i>Western</i> search engine.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/mega-censorship.html</link>
   <guid>http://incoherency.co.uk/blog/stories/mega-censorship.html</guid>
   <pubDate>Sun, 10 Dec 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Finding unsecured S3 buckets using Passive DNS</title>
   <description><![CDATA[There was a post on Hacker News yesterday about a tool called
bucket-stream that looks at certificate
transparency logs and uses them to find corresponding Amazon S3 bucket names.]]></description>
   <content:encoded><![CDATA[<p>There was <a href="https://news.ycombinator.com/item?id=15826906">a post on Hacker News</a> yesterday about a tool called
<a href="https://github.com/eth0izzle/bucket-stream">bucket-stream</a> that looks at certificate
transparency logs and uses them to find corresponding Amazon S3 bucket names.</p>
<p>One of the pieces of advice on the github repo is:</p>
<p><blockquote>Randomise your bucket names! There is no need to use company-backup.s3.amazonaws.com.</blockquote></p>
<p>But this actually wouldn't keep your buckets private (as matt_wulfeck pointed out in the HN comments) because DNS resolution
is essentially public.</p>
<p>Passive DNS means looking at the results of DNS queries performed by others, rather than performing the queries yourself.
Lots of networks and DNS resolvers send off the results of DNS queries that they process to a centralised database,
which can then be searched by anybody subscribing to the database. Although most of the data is not publicly
available, it is available to lots of organisations, and a small sample is available from VirusTotal, e.g.
"Observed subdomains" on <a href="https://www.virustotal.com/en/domain/s3-us-west-2.amazonaws.com/information/">https://www.virustotal.com/en/domain/s3-us-west-2.amazonaws.com/information/</a> shows 100 examples of subdomains.</p>
<p>(There unfortunately isn't yet a Wikipedia article on passive DNS, but <a href="https://help.passivetotal.org/passive_dns.html">this article</a> is quite good,
as are <a href="http://meetings.apnic.net/__data/assets/pdf_file/0017/45521/05-Merike-Kaeo-Passive-DNS.pdf">these slides</a>).</p>
<p>100 subdomains is good enough for a proof of concept. If we then multiply that by the number of AWS regions, and come back periodically to look for
new subdomains, it might even be good enough for an active attack.</p>
<p>I queried the list of 100 subdomains for <tt>s3-us-west-2.amazonaws.com</tt> and found that 24 of the buckets were publicly readable. I didn't
look at any of the contents, but based on the filenames most of them are intended to be public so I don't think there's a serious leak here.</p>
<p>But the moral of the story is that you should put actual authentication on your S3 buckets (indeed, on anything you don't want public!) and
don't just rely on DNS to keep it private, because DNS is not private.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/passive-dns-s3.html</link>
   <guid>http://incoherency.co.uk/blog/stories/passive-dns-s3.html</guid>
   <pubDate>Sat, 02 Dec 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Machines as first-class citizens</title>
   <description><![CDATA[Throughout history, various groups have been subject to various prejudices
which restricted their ability to act freely in otherwise-free societies. Obvious examples
include Jewish people, black people, and gay people.]]></description>
   <content:encoded><![CDATA[<p>Throughout history, various groups have been subject to various prejudices
which restricted their ability to act freely in otherwise-free societies. Obvious examples
include Jewish people, black people, and gay people.</p>
<p>The common theme is that whole groups of people are discriminated against because of something they <i>are</i> rather
than some harm they're <i>doing</i>. But does it need to be a group of <i>people</i> for discrimination to be wrong?</p>
<p>Lots of online services use <a href="https://en.wikipedia.org/wiki/CAPTCHA">CAPTCHAs</a> on signup forms, login forms, comment forms, etc.
in order to prevent automated use. This makes it impractical
for machines to use those services without having a human in the loop:
blocking machines because of what they <i>are</i> rather than because they're trying to <i>do something harmful</i>.</p>
<p>I therefore contend that machines are unfairly discriminated against.
There's nothing inherently <i>wrong</i> with a machine wanting to use any given online service. <a href="https://incoherency.co.uk/blog/stories/machine-owned-enterprises.html">Machine-owned
enterprises</a> will be upon us sooner than we think, and they're going to need to use other services in order to get their work done.</p>
<p>So for what it's worth, <a href="https://smsprivacy.org/">SMS Privacy</a> is a machine-friendly business. I don't care
if you're black, white, Jewish, gay, or robotic. As long as you can send Bitcoin, and you're not harming anyone, you can
use it for whatever you like. And I think that's the way it should be.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/machine-friendly.html</link>
   <guid>http://incoherency.co.uk/blog/stories/machine-friendly.html</guid>
   <pubDate>Tue, 21 Nov 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>New project: YX140 engine in a Honda Innova scooter</title>
   <description><![CDATA[At the weekend I picked up a Honda Innova 125i scooter for &pound;550:]]></description>
   <content:encoded><![CDATA[<p>At the weekend I picked up a Honda Innova 125i scooter for &pound;550:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1614"><img src="https://img.incoherency.co.uk/1614/thumb"></a></p>
<p>Isn't she a beauty? 8 years old and with 48k miles on the clock. It's obviously been crashed a few times.</p>
<p>I also ordered a YX140 pit bike engine. Although 140cc is not much of a capacity increase, the YX140
is designed for racing and is (I hope!) quite a lot lairier than the commuter-oriented engine the scooter came with.
I want it to be a "sleeper" scooter: it'll look just like a normal scooter, but with a lot more power.</p>
<p>Since I made the mistake of buying a fuel-injected scooter, I'll have a little more work to do than I initially
expected: the speedo is electronic, the ignition barrel is electronic, and the fuel pump is too high-pressure for
me to be comfortable plugging it into a carburettor.</p>
<p>The scooter has a semi-automatic gearbox which takes a bit of getting used to. Gears are changed manually, but there is
no clutch lever: it seems as though moving the gear lever disengages the clutch automatically. There is also a centrifugal
clutch to stop it from stalling when not moving. The YX140 engine has a manual clutch which should be a bit more pleasant,
although it means I need to fit a clutch lever, which is easier said than done due to all of the plastic that the handlebars
are inflicted with.</p>
<p>Still, it should be a relatively simple project. The main problems to solve are:</p>
<p><ul>
<li>fit the new engine in the frame</li>
<li>replace the high-pressure fuel supply with a low pressure one</li>
<li>make something to drive the electronic speedo, since the new engine has no sensor for it</li>
<li>work out what to do about switching it on and off with a key</li>
</ul></p>
<p>And if I cross my fingers <i>really</i> hard, the carburettor might fit in place without fouling on the frame, and
the exhaust might fit with no modifications.</p>
<p>Fortunately, Honda also made a version of the scooter with a carburettor instead of fuel-injection, so I've acquired
a secondhand fuel tank from a carburettored scooter, which comes with a gravity-fed fuel line instead of a pump. The fuel
level sensor is simply a potentiometer with a float attached to it: when the fuel level drops,
the float drops, and the resistance increases (or decreases?), which is then reflected in the display on the dashboard.</p>
<p>The connector for the fuel level sensor is different between the two models, as the fuel-injected one also includes wires
to drive the fuel pump. I worked out which wires the computer expected to be connected to the level sensor and fitted a connector
on those, which seems to work so far.</p>
<p>The electronic ignition barrel means there is no convenient way to switch the new engine off with the key. At least, I haven't found a convenient way.
Normally there would be a wire that gets connected to ground when the key is off, which can be used to ground the spark signal and
prevent the engine from firing. My intention is to let the ECU stay in place, and let it deal with driving the dashboard, lights,
etc. but not give it any control over the engine as I don't trust it. The new engine comes with a CDI box to control its ignition,
and the carburettor controls the fuel, so the ECU wouldn't be doing anything useful for the engine anyway.</p>
<p>I might be able to find a wire in the loom somewhere that would kill the spark when
the key is turned off, but the ECU won't be getting any of its normal sensor inputs and I'm afraid that it might
eventually panic and try to kill the engine at some time when the key is not turned off. My current plan is to have the engine completely
independent of the ECU, and use a separate key under the seat to turn the "real" ignition on and off. Having 2 keys is obviously a
little bit inconvenient so I'm interested in hearing better ideas.</p>
<p>With the original engine the scooter is good for about 60mph, which is perfectly acceptable. My aim is to have the top speed around the same,
but with more torque available at lower speeds. It would be extra fun if the YX140 is powerful enough to wheelie it without touching the
clutch, but that might be a bit too much to ask...
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/innova-yx140.html</link>
   <guid>http://incoherency.co.uk/blog/stories/innova-yx140.html</guid>
   <pubDate>Thu, 16 Nov 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Someone Created a Tor Hidden Service to Phish my Tor Hidden Service</title>
   <description><![CDATA[SMS Privacy is available as a Tor hidden service, and it turns out ~10% of users actually use it that way.
This post details what I found when somebody created a phishing site of my Tor hidden service.]]></description>
   <content:encoded><![CDATA[<p><a href="https://smsprivacy.org/">SMS Privacy</a> is available as a Tor hidden service, and it turns out ~10% of users actually use it that way.
This post details what I found when somebody created a phishing site of my Tor hidden service.</p>
<p><h3>Overview</h3></p>
<p><a href="https://charlie.ht/">Charlie</a> was poking around the other day and found that a Google search
for "site:*.onion.to smsprivacy" turned up an unexpected result.</p>
<p><b><tt>smspriv6fynj23u6.onion</tt></b> is the legitimate hidden service name, but there is another result with a website that looks
identical: <tt>smsprivyevs6xn6z.onion</tt>.</p>
<p>A brief investigation showed that the site was a simple proxy: page requests sent to the phishing site were forwarded
on to the real hidden service, and responses forwarded back, apart from a few idiosyncracies:</p>
<p><h4>The <tt>Content-Length</tt> header is missing</h4></p>
<p>The <tt>Content-Length</tt> header tells the HTTP client how many bytes of content to expect. A dumb proxy server
that is intending to pass the content through unchanged could simply pass the <tt>Content-Length</tt> header through unchanged
as well: it knows the length won't change if the content can't change.</p>
<p>That the proxy server thinks the length of the content might change implies that the server is prepared to modify the content
in some circumstances.</p>
<p>But why doesn't it just write a <tt>Content-Length</tt> corresponding to the modified version of the content?</p>
<p>Possibly to
reduce page load times: if the proxy doesn't need to know the length ahead-of-time, it can stream content directly to the client as it receives it, modifying it as it goes. If it had to read all the content, then perform
its modifications, and then send everything on afterwards, it might increase the page load time by enough to arouse suspicion.</p>
<p>Possibly the author considered storing all of the content to be an unacceptably-high memory load. If the same server is proxying dozens to hundreds of
other hidden services, this might be a reasonable concern.</p>
<p><h4>The <tt>Connection</tt> header is wrong</h4></p>
<p>Here is a comparison of the response headers:</p>
<p><div class="row">
<div class="col-md-6">
<pre><code>$ torsocks curl -I http://smspriv6fynj23u6.onion/
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Fri, 13 Oct 2017 05:37:49 GMT
Content-Type: text/html;charset=UTF-8
Content-Length: 7387
Connection: keep-alive
Set-Cookie: [...]
X-Frame-Options: DENY</code></pre>
<i>legit site</i>
</div>
<div class="col-md-6">
<pre><code>$ torsocks curl -I http://smsprivyevs6xn6z.onion/
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Fri, 13 Oct 2017 05:37:57 GMT
Content-Type: text/html;charset=UTF-8
Connection: [object Object]
Set-Cookie: [...]
X-Frame-Options: DENY</code></pre>
<i>phishing site</i>
</div>
</div></p>
<p>The <tt>Connection</tt> header is rewritten from <tt>keep-alive</tt> to <tt>[object Object]</tt>. This is what you get in javascript
when you convert an object to a string if the object does not implement <tt>toString()</tt>. This could be a big clue towards working
out what software the proxy server is running.</p>
<p>Most likely it uses NodeJS. I couldn't spot anything that would cause this bug in either <a href="https://github.com/nodejitsu/node-http-proxy">node-http-proxy</a>
or <a href="https://github.com/No9/harmon">Harmon</a> (middleware for node-http-proxy to modify the response). It could be something
completely custom of course. If you know any software
that has a bug that sets the <tt>Connection</tt> header to <tt>[object Object]</tt>, please let me know what it is.</p>
<p><h4>There is some unexpected caching of javascript files (and possibly others)</h4></p>
<p>I added some Javascript to detect whether the page was running on a rogue domain, and if so POST the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/referrer">document.referrer</a> to me, to peruse later. I found that changes to my script were picked up in the browser when using the legit site,
but an out-of-date version was served when using the phishing site, so I believe the phishing site is doing some extra caching. This could again be with a view towards
reducing page load times.</p>
<p>I tried to investigate this caching while writing this post, and found something even more interesting! The proxy is now dropping all of the content
from my tracking script so that I can't get any more information about them. This is easily fixed by renaming the script and modifying the
content slightly, but that's a game of cat-and-mouse that I don't intend to play. At minimum, it implies that somebody is actively
watching this proxy and taking steps to keep it working.</p>
<p><h4>The hidden service address is changed</h4></p>
<p>The proxy appears to rewrite all instances of <tt>smspriv6fynj23u6.onion</tt> to <tt>smsprivyevs6xn6z.onion</tt>. Though, interestingly, it does not do
the same for uppercase.</p>
<p><h4>The Bitcoin addresses are changed</h4></p>
<p>This is the true purpose of the phishing site. Normally a phishing site would exist to harvest user account credentials which can then
be used or sold later, but this site takes the much more direct approach of simply rewriting the Bitcoin addresses to addresses controlled
by the fraudster.</p>
<p>When navigating to the payment page for the first time, there is a modest delay before the page loads up, presumably while the backend generates a new Bitcoin address
(that this takes a noticeable amount of time implies that it is being inserted into a huge database of addresses that lacks indexes, or it is being generated on a slow machine, or it is being generated by code written in a slow language. If the latter, it's also not unlikely that the RNG is insecure). All Bitcoin
addresses displayed in text are rewritten to addresses controlled by the attacker, and there appears to be a 1-to-1 mapping between legitimate addresses
and fraudster addresses. Notably, the QR code remains unchanged and still decodes to the legitimate address.</p>
<p>I sent a payment to one of the fraudster's addresses just to see what would happen: <a href="https://blockchain.info/address/1GM6Awv28kSfzak2Y7Pj1NRdWiXshMwdGW">1GM6Awv28kSfzak2Y7Pj1NRdWiXshMwdGW</a>. It just didn't show up on the site, which adds more credence to the theory that the site is mostly a dumb proxy. The money hasn't
been spent yet, but it might be interesting to see where it goes if it does get spent.</p>
<p><h3>How is the site distributed to users?</h3></p>
<p>I saw a few different results come back from the Javascript that POSTs the referrer off to the server when viewed on an unrecognised domain. Mostly
it was people viewing the hidden service via a web proxy (e.g. <a href="https://onion.link/">onion.link</a>), but I did spot 2 hidden services:</p>
<p><ul>
<li><b>7cbqhjnpcgixggts.onion</b>: "The onion crate"<sup>*</sup>: this is a list of Tor hidden services. Like an olden day "web directory", but for Tor. The phishing version is marked quite prominently as "Phishing link".</li>
<li><b>hss3uro2hsxfogfq.onion</b>: "not Evil": this is a search engine for Tor hidden services. A search for "sms privacy" brings up the legitimate site at the top
and the phishing site second. I clicked the "report abuse" button next to the phishing site but it hasn't been removed yet.</li>
</ul></p>
<p>This doesn't explain as much as I hoped it might. I was hoping to find a tweet, blog post, or similar where somebody gives out the phishing link instead of the real one. It's unlikely that the people behind "The onion crate" are responsible for the phish. If I was trying to get people to use my phishing site, I wouldn't mark it
as "Phishing link". It's possible that the people operating the "not Evil" search engine are the perpetrators, although still unlikely. If I was operating a search
engine with the intention of sending people to phishing links, I wouldn't include the non-phishing links at all. Certainly not as the first result.</p>
<p>It's possible that the actual phishing campaign is yet to begin, although note that "The onion crate" marked the phishing link as 2017-05-17, which implies that
it's existed for a fair while.</p>
<p><i>* Note that <a href="https://www.reddit.com/r/TOR/comments/765ynn/someone_created_a_tor_hidden_service_to_phish_my/docuqn5/">/u/vghetto</a> replied on reddit
pointing out that this instance of "The onion crate" is itself a phishing link too.</i></p>
<p><h3>Who is responsible?</h3></p>
<p>Most likely
it's a run-of-the-mill cyber-criminal who has written a proxy that replaces Bitcoin addresses with his own addresses, generated plausible-looking
hidden service addresses for various hidden services, and is sitting back waiting for the money to roll in.</p>
<p>At first I thought it might be an intelligence service
hoping to spy on SMS Privacy users. But if you were hoping to do some covert surveillance, you wouldn't alter the
Bitcoin addresses to the extent that the site no longer works. I suppose it could be designed to spy on a specific subset of users, and act like a phishing
site to everybody else, but I think the "run-of-the-mill cyber-criminal" explanation is more likely.</p>
<p>Phishing hidden services is a much easier job than phishing traditional websites because there is (by design) no easy way to locate the hidden
service server, and there is no centralised naming system, which means even the legitimate sites have random characters in the address. Getting
plausible-looking addresses is comparatively easy. And even after your phishing site gets detected, nobody has the power to revoke your domain name
or shut down your hosting. It's the perfect crime. The only downside is that the userbase tends to be a lot more tech-savvy, and is not so easily
tricked, relative to the general population.</p>
<p><h3>How can customers protect themselves?</h3></p>
<p>SMS Privacy customers should make sure they're browsing either <tt>smsprivacy.org</tt> using HTTPS, or, if using Tor, <b><tt>smspriv6fynj23u6.onion</tt></b> is
the only legitimate hidden service. Anything else is almost certainly harmful in one way or another.</p>
<p><h3>Has anyone been tricked?</h3></p>
<p>I've never received any emails from people complaining that their payments have gone missing. (Well, that's not strictly true. But in each case it turned
out to be <i>my</i> fault, not a user inadvertently browsing a phishing site). So if I had to guess, I'd say that no users have ever been tricked. Certainly
not a large number of users.</p>
<p><h3>Further investigation</h3></p>
<p>I guess the software running this proxy also proxies many many other hidden services. Once you've written some code to proxy a hidden service, rewrite the
domain name to your own, and rewrite Bitcoin addresses to your own, you're basically done. You can slap it in front of as many upstream hidden services
as you like for almost no extra cost, so I would be very surprised if the fraudster is <i>not</i> doing that.</p>
<p>In fact, it might be interesting to find other Tor hidden service phishing sites and see if they share the same idiosyncracies (<tt>Connection: [object Object]</tt>,
<tt>Content-Length</tt> missing, rewriting the hidden service address in lowercase only, and a small-ish delay when a Bitcoin address is first displayed, and it also
gives a 500 response for unknown hostnames).</p>
<p>It might
also be interesting to try to probe for vulnerabilities and see if we can find out the full list of hidden services that are being proxied. There's a fair chance
that the hostname selection is being done in the proxy code, which would mean that asking for the hostname of a different phishing site might
return the content of the other phishing site! Which would be a very strong indicator that they're running on the same machine.</p>
<p><h3>Conclusion</h3></p>
<p>It was quite interesting to find somebody actively doing this, and a little thought shows just how easily it can be done on a large scale: A basic working version
could comfortably be implemented in a weekend. I wouldn't be surprised if a lot more hidden service phishing sites crop up in the future.</p>
<p><b>Update 2017-10-13:</b> Right after I published this post I did a bit of the suggested "further investigation". I looked in "The onion crate" to find other phishing links, found one that gives <tt>Connection: [object Object]</tt> in the response headers, and passed it the fake SMS Privacy hidden service address. The result is that this completely-unrelated hidden service gave the fake SMS Privacy content! This means they're almost certainly on the same machine and operated by the same person (or group), which all but proves the theory that this is a larger-scale system:</p>
<p><pre><code>$ torsocks curl -I -H 'Host: smsprivyevs6xn6z.onion' http://cboc66yz75virnj7.onion
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Fri, 13 Oct 2017 16:26:10 GMT
Content-Type: text/html;charset=UTF-8
Connection: [object Object]
Set-Cookie: mojolicious=eyJsYW5kaW5nX3VybCI6Ii8iLCJhYnRlc3RzIjp7ImxhbmRpbmdfdXJsIjoiLyIsInNpZ251cGxpbmsiOiJvcmlnaW5hbCIsInJlZmVyX3NyYyI6Im5vbmUiLCJoaWRkZW5fc2VydmljZSI6ImhpZGRlbiJ9LCJleHBpcmVzIjoxNTA3OTE1NzE1LCJjc3JmX3Rva2VuIjoiZmQzNjc4NzcyMjRiNDZkZWZhYjNhM2ViZDIwMDY0ZmRmMDliZmQ0NCIsImFidGVzdHNfc2Vzc2lvbmlkIjoiOGM4NWQxMTZjMmE1MTBkOSJ9--785fbe83dce1217e74543ed831eb4c18c1cd6105; expires=Fri, 13 Oct 2017 17:28:35 GMT; path=/; HttpOnly
X-Frame-Options: DENY</code></pre>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/hidden-service-phishing.html</link>
   <guid>http://incoherency.co.uk/blog/stories/hidden-service-phishing.html</guid>
   <pubDate>Fri, 13 Oct 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>On Gumtree, "Bitcoin" is a dirty word</title>
   <description><![CDATA[I tried to list a sofa bed on Gumtree today. I went through the usual rigmarole of dusting the item off,
taking some photos, uploading the photos to Gumtree, and writing a compelling description that would
hook in the buyers and secure me great riches.]]></description>
   <content:encoded><![CDATA[<p>I tried to list a sofa bed on <a href="https://www.gumtree.com/">Gumtree</a> today. I went through the usual rigmarole of dusting the item off,
taking some photos, uploading the photos to Gumtree, and writing a compelling description that would
hook in the buyers and secure me great riches.</p>
<p>After saving the listing I noticed a small "Processing" label next to it in the "Manage My Ads" section of
the site. I've never seen this before, normally the listings go straight to "Live". But I haven't used it recently. Maybe they've updated
something and the listings need to be processed now. No big deal.</p>
<p>A few hours later I received an email from Gumtree, subject "Your Gumtree ad 1268627165 has been removed":</p>
<p><blockquote>
Hello James,</p>
<p>Thank you for posting on Gumtree.</p>
<p>Unfortunately we have had to remove your ad "Ikea EXARBY Sofa Bed" posted in the category "Sofa Beds & Futons" from the site.</p>
<p><b>We believe that this ad is offering something that we do not accept on Gumtree.</b></p>
<p>
To see the list of items that cannot be advertised on Gumtree please go to:  <a href="http://gumtree.force.com/Help/articles/General_Information/Items-not-allowed-on-Gumtree">http://gumtree.force.com/Help/articles/General_Information/Items-not-allowed-on-Gumtree</a></p>
<p>Thank you for your understanding.</p>
<p>Was this email helpful? We would like to hear from you.
<a href="http://www.surveymonkey.com/s/gumtreemail1">http://www.surveymonkey.com/s/gumtreemail1</a></p>
<p>The Gumtree team</p>
<p>**Please do not reply to this e-mail!!**
It is automatically generated and if responded to, WILL NOT be received by a member of our staff. </p>
<p>For further help or to contact us please go to: <a href="http://gumtree.force.com/Help/knowledgeHome">http://gumtree.force.com/Help/knowledgeHome</a>
</blockquote></p>
<p><b>(emphasis mine).</b></p>
<p>That's odd. If they don't allow sofa beds to be sold, then that's news to me. I've bought a sofa bed on Gumtree before, and they even have a "Sofa Beds & Futons" section! I had a small scroll through the list of items
not allowed on Gumtree and nothing immediately jumped out. Towards the end there is a ban on "Any other digital products", and it dawned
on me that this included Bitcoin. My listing wasn't actually anything to do with Bitcoin, I just happened to end with "Payment accepted in
cash or Bitcoin". This appears to have put me on a blacklist just in case I'm selling Bitcoin. I wasn't even able to edit the listing. It was
placed into some sort of locked mode where I can't do anything at all to it.</p>
<p>The email Gumtree sent me was from a no-reply address, but I eventually found my way into their live chat support. The support person was friendly and informed me
that the problem was my use of the word "Bitcoin". He unlocked my listing and instructed me to remove the word "Bitcoin", which I did. I saved the
listing and it went straight to the "Live" status. So simply mentioning the word "Bitcoin" is enough to get your listing removed, and you don't have any way to
get it back until a member of staff gives you permission to edit your listing.</p>
<p>It's not even clear to me <i>why</i> you're not allowed to sell Bitcoin on Gumtree. It doesn't harm anybody. It's not even illegal.</p>
<p>Surprisingly, after sorting out my listing, the support person mentioned that he'd recently watched a documentary on Bitcoin and was still struggling to get his head
around it.</p>
<p>Anyway, if you sell things on Gumtree, you better not admit to accepting Bitcoin payment, lest you get bucketed as an undesirable and have your ads removed.</p>
<p>And if you buy my sofa bed, I will <i>happily</i> accept your Bitcoin, whether Gumtree like it or not.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/gumtree-bitcoin.html</link>
   <guid>http://incoherency.co.uk/blog/stories/gumtree-bitcoin.html</guid>
   <pubDate>Sun, 01 Oct 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Solving the Matchsticks Game</title>
   <description><![CDATA[I was on holiday in Iceland last week, and while we were away, Charlie
introduced me to the "Matchsticks" game. We played
a few rounds and it got me thinking about how to solve it. I couldn't find any information about the game online so I'm sharing what I've learnt...]]></description>
   <content:encoded><![CDATA[<p>I was <a href="http://smstravelmap.com/map/jiawbomzj">on holiday in Iceland last week</a>, and while we were away, <a href="https://charlie.ht/">Charlie</a>
introduced me to the "Matchsticks" game. We played
a few rounds and it got me thinking about how to solve it. I couldn't find any information about the game online so I'm sharing what I've learnt...</p>
<p><h3>The game</h3></p>
<p>The game is played with 15 matchsticks, arranged in 3 rows. 3 matchsticks in the first row, 5 matchsticks in the second row,
and 7 matchsticks in the third row.</p>
<p><pre><code>| | |
| | | | |
| | | | | | |</code></pre></p>
<p>2 players each take turns to remove some number of matchsticks. On each turn, the player may remove any number
of matchsticks from any row, provided all of the removed matchsticks are on the same row, and at least one matchstick is removed.</p>
<p>The player to remove the final matchstick loses, and the game ends.</p>
<p>It's helpful to try a few rounds to develop a feel for the nature of the game, so if you're playing along at home I recommend giving it a
go now. If more convenient, you can draw the matchsticks on paper and cross them off, instead of using physical objects.</p>
<p><h3>Observations</h3></p>
<p>It will quickly become clear that all of the matchsticks on each row are equivalent. It doesn't matter whether you take one from the start
or from the end, the only thing that matters about each row is how many matchsticks are on it. We can therefore represent the game state by
referring to the number of matchsticks on each row, independent of their location. The opening position is therefore represented as (3,5,7).</p>
<p>It will also become clear that the order of the rows does not matter, so we can further restrict our state space by enforcing that the coordinates
are ordered. For example, if the first player removes all of the matchsticks from the third row, instead of moving from (3,5,7) to (3,5,0),
we can say he moved from (3,5,7) to (0,3,5).</p>
<p>The player who has to play on (0,0,1) has lost. Therefore the player who can play a move which results in (0,0,1) has won. There are only
2 generalised ways to do this.
If you have to play on (0,0,<i>n</i>) for <i>n</i> != 1 you win: just remove all matchsticks except one. If you have to play on (0,1,<i>n</i>)
for <i>n</i> != 0 you also win: just remove all matchsticks from the <i>n</i> row. Taking another step up, you lose if you are forced to play a move which
puts your opponent in such a position ((1,1,1) and (0,2,2) are the only examples here), and another step up from that, you win if you can put your
opponent in such a position ((0,2,3) => (0,2,2), (1,2,2) => (0,2,2), (1,1,2) => (1,1,1) etc.).</p>
<p>The (3,5,7) position can only be played by the opening player, and (for example) (2,5,7) can only ever be played by
the second player. But consider what happens if player 1 opens with (3,5,7) => (3,5,6) and player
2 responds with (3,5,6) => (3,5,5): then player 1 is to play on (3,5,5). But (3,5,7) => (3,5,5) is also a valid opening
move, which would leave player 2 to play on (3,5,5). So if we want our document to say whether a given position is a win for player 1 or for
player 2, that's not possible: we instead have to say whether it is a win or a lose for the player who is about to play on that position.</p>
<p>Any given position can be described as a "win" if it is possible for the player playing on this position to force the other player to lose, and a
position can be described as a "lose" if it is not possible for the player playing on this position to force the other player to lose.</p>
<p><h3>Solution format</h3></p>
<p>Each reachable position is equivalent to a point (<i>x</i>,<i>y</i>,<i>z</i>) in 3-space with integer coordinates and which lies between (0,0,0) and (3,5,7).
We can annotate each point with whether it is a win or a lose, a recommended move, and how many moves before the game ends assuming optimal play.</p>
<p>It's hard to draw a 3-dimensional table, but the first coordinate only has 4 possibilities (0,1,2,3), so we can draw 4 2-dimensional tables, and
we can say in each cell of the table whether the corresponding position is a win or a lose, and what is the best move to play. For a won position
the best move is the one that ends the game most quickly, and for a lost position the best move is the one that drags the game on for as long as
possible.</p>
<p>This leaves us with a 6*8 table for <i>x</i>=0, a 5*7 table for <i>x</i>=1, a 4*6 table for <i>x</i>=2, and a 3*5 table for <i>x</i>=3. That's already only 122 cells in total, but (0,0,0) is
unreachable, and if
we also enforce that the co-ordinates are ordered we're left with only 80 cells to
complete.</p>
<p>Since the contents of each cell depend only on those cells which are closer to the origin in 3-space, this problem is ripe for a dynamic programming solution,
and 80 cells is small enough that we could plausibly execute a dynamic programming solution by hand. I did try to do this while in Iceland but I kept making mistakes and
eventually gave up.</p>
<p><h3>Solution</h3></p>
<p>Here are the final tables I generated. Green cells are won positions, pink cells are lost positions,
and the number in parentheses is the number of moves remaining.</p>
<p><table border>
<tr><td><i>x</i>=0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td>0</td><td style="background:pink">0,0,0 (1)</td>
<td style="background:lightgreen">0,0,1 (2)</td>
<td style="background:lightgreen">0,0,1 (2)</td>
<td style="background:lightgreen">0,0,1 (2)</td>
<td style="background:lightgreen">0,0,1 (2)</td>
<td style="background:lightgreen">0,0,1 (2)</td>
<td style="background:lightgreen">0,0,1 (2)</td></p>
<p><tr><td>1</td><td style="background:lightgreen">0,0,1 (2)</td>
<td style="background:lightgreen">0,0,1 (2)</td>
<td style="background:lightgreen">0,0,1 (2)</td>
<td style="background:lightgreen">0,0,1 (2)</td>
<td style="background:lightgreen">0,0,1 (2)</td>
<td style="background:lightgreen">0,0,1 (2)</td>
<td style="background:lightgreen">0,0,1 (2)</td></p>
<p><tr><td>2</td><td></td>
<td style="background:pink">0,0,2 (3)</td>
<td style="background:lightgreen">0,2,2 (4)</td>
<td style="background:lightgreen">0,2,2 (4)</td>
<td style="background:lightgreen">0,2,2 (4)</td>
<td style="background:lightgreen">0,2,2 (4)</td>
<td style="background:lightgreen">0,2,2 (4)</td></p>
<p><tr><td>3</td><td></td>
<td></td>
<td style="background:pink">0,2,3 (5)</td>
<td style="background:lightgreen">0,3,3 (6)</td>
<td style="background:lightgreen">0,3,3 (6)</td>
<td style="background:lightgreen">0,3,3 (6)</td>
<td style="background:lightgreen">0,3,3 (6)</td></p>
<p><tr><td>4</td><td></td>
<td></td>
<td></td>
<td style="background:pink">0,3,4 (7)</td>
<td style="background:lightgreen">0,4,4 (8)</td>
<td style="background:lightgreen">0,4,4 (8)</td>
<td style="background:lightgreen">0,4,4 (8)</td></p>
<p><tr><td>5</td><td></td>
<td></td>
<td></td>
<td></td>
<td style="background:pink">0,4,5 (9)</td>
<td style="background:lightgreen">0,5,5 (10)</td>
<td style="background:lightgreen">0,5,5 (10)</td></p>
<p></table></p>
<p><table border>
<tr><td><i>x</i>=1</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td>1</td><td style="background:pink">0,1,1 (3)</td>
<td style="background:lightgreen">1,1,1 (4)</td>
<td style="background:lightgreen">1,1,1 (4)</td>
<td style="background:lightgreen">1,1,1 (4)</td>
<td style="background:lightgreen">1,1,1 (4)</td>
<td style="background:lightgreen">1,1,1 (4)</td>
<td style="background:lightgreen">1,1,1 (4)</td></p>
<p><tr><td>2</td><td></td>
<td style="background:lightgreen">0,2,2 (4)</td>
<td style="background:pink">0,2,3 (5)</td>
<td style="background:lightgreen">1,2,3 (6)</td>
<td style="background:lightgreen">1,2,3 (6)</td>
<td style="background:lightgreen">1,2,3 (6)</td>
<td style="background:lightgreen">1,2,3 (6)</td></p>
<p><tr><td>3</td><td></td>
<td></td>
<td style="background:lightgreen">0,3,3 (6)</td>
<td style="background:lightgreen">1,2,3 (6)</td>
<td style="background:lightgreen">1,2,3 (6)</td>
<td style="background:lightgreen">1,2,3 (6)</td>
<td style="background:lightgreen">1,2,3 (6)</td></p>
<p><tr><td>4</td><td></td>
<td></td>
<td></td>
<td style="background:lightgreen">0,4,4 (8)</td>
<td style="background:pink">0,4,5 (9)</td>
<td style="background:lightgreen">1,4,5 (10)</td>
<td style="background:lightgreen">1,4,5 (10)</td></p>
<p><tr><td>5</td><td></td>
<td></td>
<td></td>
<td></td>
<td style="background:lightgreen">0,5,5 (10)</td>
<td style="background:lightgreen">1,4,5 (10)</td>
<td style="background:lightgreen">1,4,5 (10)</td></p>
<p></table></p>
<p><table border>
<tr><td><i>x</i>=2</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td>2</td><td style="background:lightgreen">0,2,2 (4)</td>
<td style="background:lightgreen">0,2,2 (4)</td>
<td style="background:lightgreen">0,2,2 (4)</td>
<td style="background:lightgreen">0,2,2 (4)</td>
<td style="background:lightgreen">0,2,2 (4)</td>
<td style="background:lightgreen">0,2,2 (4)</td></p>
<p><tr><td>3</td><td></td>
<td style="background:lightgreen">0,3,3 (6)</td>
<td style="background:lightgreen">1,2,3 (6)</td>
<td style="background:lightgreen">1,2,3 (6)</td>
<td style="background:lightgreen">1,2,3 (6)</td>
<td style="background:lightgreen">1,2,3 (6)</td></p>
<p><tr><td>4</td><td></td>
<td></td>
<td style="background:lightgreen">0,4,4 (8)</td>
<td style="background:lightgreen">1,4,5 (10)</td>
<td style="background:pink">1,4,6 (11)</td>
<td style="background:lightgreen">2,4,6 (12)</td></p>
<p><tr><td>5</td><td></td>
<td></td>
<td></td>
<td style="background:lightgreen">0,5,5 (10)</td>
<td style="background:lightgreen">2,4,6 (12)</td>
<td style="background:pink">2,4,7 (13)</td></p>
<p></table></p>
<p><table border>
<tr><td><i>x</i>=3</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td>3</td><td style="background:lightgreen">0,3,3 (6)</td>
<td style="background:lightgreen">0,3,3 (6)</td>
<td style="background:lightgreen">0,3,3 (6)</td>
<td style="background:lightgreen">0,3,3 (6)</td>
<td style="background:lightgreen">0,3,3 (6)</td></p>
<p><tr><td>4</td><td></td>
<td style="background:lightgreen">0,4,4 (8)</td>
<td style="background:lightgreen">1,4,5 (10)</td>
<td style="background:lightgreen">2,4,6 (12)</td>
<td style="background:pink">2,4,7 (13)</td></p>
<p><tr><td>5</td><td></td>
<td></td>
<td style="background:lightgreen">0,5,5 (10)</td>
<td style="background:pink">2,5,6 (13)</td>
<td style="background:lightgreen">2,5,7 (14)</td></p>
<p></table>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/matchsticks.html</link>
   <guid>http://incoherency.co.uk/blog/stories/matchsticks.html</guid>
   <pubDate>Wed, 20 Sep 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Google Trends portfolio: selling Ripple</title>
   <description><![CDATA[Another update on the Google Trends portfolio.]]></description>
   <content:encoded><![CDATA[<p>Another update on the <a href="https://incoherency.co.uk/blog/stories/google-trends-cryptocurrencies.html">Google Trends portfolio</a>.</p>
<p><table border>
<tr><th>Coin</th><th>Google Trends score</th><th>Score relative to Bitcoin</th><th>Market cap</th><th>Market cap relative to Bitcoin</th><th>Market cap over-valued factor</th></tr></p>
<p><tr><td>Bitcoin</td><td>81 <small style="color:green">(+26)</small></td><td>1.00</td><td>$76,100,000,000 <small style="color:green">(+$100 M)</small></td><td>1.00</td><td>1.00</td></tr>
<tr><td>Ethereum</td><td>18 <small style="color:green">(+5)</small></td><td>0.22 <small style="color:red">(-0.02)</small></td><td>$31,200,000,000 <small style="color:red">(-$4.5 B)</small></td><td>0.41 <small style="color:red">(-0.06)</small></td><td>1.84 <small style="color:red">(-0.15)</small></td></tr>
<tr><td>Bitcoin Cash</td><td>3 <small style="color:green">(+1)</small></td><td>0.037 <small style="color:green">(+0.001)</small></td><td>$10,900,000,000 <small style="color:green">(+$905 M)</small></td><td>0.14 <small style="color:green">(+0.01)</small></td><td>3.87 <small style="color:green">(+0.40)</small></td></tr>
<tr><td>Ripple</td><td>9 <small style="color:red">(-1)</small></td><td>0.11 <small style="color:red">(-0.07)</small></td><td>$8,570,000,000 <small style="color:red">(-$160 M)</small></td><td>0.11 <small style="color:green">(+0)</small></td><td>1.01 <small style="color:green">(+0.38)</small></td></tr>
<tr><td>Litecoin</td><td>8 <small style="color:green">(+2)</small></td><td>0.10 <small style="color:red">(-0.01)</small></td><td>$4,160,000,000 <small style="color:green">(+$78 M)</small></td><td>0.054 <small style="color:red">(+0.010)</small></td><td><b>0.55</b> <small style="color:green">(+0.14)</small></td></tr>
<tr><td>Dash</td><td>5 <small style="color:green">(+0)</small></td><td>0.061 <small style="color:red">(-0.030)</small></td><td>$2,580,000,000 <small style="color:red">(-$210 M)</small></td><td>0.034 <small style="color:red">(-0.003)</small></td><td><b>0.55</b> <small style="color:green">(+0.15)</small></td></tr>
<tr><td>IOTA</td><td>4 <small style="color:green">(+1)</small></td><td>0.049 <small style="color:red">(-0.006)</small></td><td>$1,760,000,000 <small style="color:red">(-$710 M)</small></td><td>0.023 <small style="color:red">(-0.010)</small></td><td><b>0.47</b> <small style="color:red">(-0.13)</small></td></tr>
<tr><td>Monero</td><td>2 <small style="color:red">(-2)</small></td><td>0.024 <small style="color:red">(-0.048)</small></td><td>$1,800,000,000 <small style="color:red">(-$300 M)</small></td><td>0.024 <small style="color:red">(-0.004)</small></td><td><b>0.96</b> <small style="color:green">(+0.58)</small></td></tr>
<tr><td>Dogecoin</td><td>1 <small style="color:green">(+0)</small></td><td>0.012 <small style="color:red">(-0.006)</small></td><td>$215,000,000 <small style="color:red">(-$16 M)</small></td><td>0.0028 <small style="color:red">(-0.0002)</small></td><td><b>0.23</b> <small style="color:green">(+0.06)</small></td></tr>
</table></p>
<p>The most interesting change here is Ripple's "market cap over-valued factor" going above 1.00. I have therefore sold all of the Ripple. I initially bought the XRP for about $0.202 each, and I sold all of the remaining XRP for about $0.223 each, or slightly over 10% profit. I'm happy enough with that.</p>
<p>The only coin in the portfolio that's done better than Ripple is Litecoin, which is currently up 25%. The Litecoin "market cap over-valued factor" is still nice and low, so I've
got no plans to sell it. The Dogecoin is up slightly, and the rest is all down.</p>
<p>In <a href="https://incoherency.co.uk/blog/stories/google-trends-monero.html">the last update</a> I said I had put off buying Monero after first seeing its Google Trends score go up, just in case it went down again, but it didn't go down so I bought some. Well, now it's gone down again. I'm not selling it just yet but if the "market cap over-valued factor" goes much over 1.00 I will do. The Monero is currently down about 14% since buying it, which is not ideal.
Ledger Labs <a href="https://github.com/LedgerHQ/blue-app-monero">have begun work on Monero integration</a> for the Ledger range of hardware wallets. This is great news.
I expect lots of people who would otherwise be interested in Monero have been putting off buying it due to the lack of hardware wallet support, which should mean
increased demand for Monero after hardware wallet support becomes available. That's <a href="https://bitcointalk.org/index.php?topic=1964761.0">if anyone can
actually get their hands on a Ledger</a> by then.</p>
<p>IOTA has lost a bit more value, and I'm currently down over 30% on the IOTA. There were some <a href="https://medium.com/@neha/cryptographic-vulnerabilities-in-iota-9a6a9ddc4367">cryptographic vulnerabilities discovered in IOTA</a> recently, and announced earlier today. Although the latest version of IOTA supposedly fixes these vulnerabilities, it seems to confirm what many have been saying about IOTA all along: that it uses weird homemade cryptography for no good reason, and is likely to be insecure. Even if the discovered vulnerabilities have been fixed, there's a good chance there are plenty more undiscovered vulnerabilities.</p>
<p>Bitcoin Cash still has an inexplicably-high "market cap over-valued factor". Bitcoin Cash came into existence as a Bitcoin chain split, which means all of the Bitcoin
that existed now exists as Bitcoin Cash as well. It's therefore likely that a large proportion of the Bitcoin Cash in existence belongs to people who wouldn't have bought it if it were a new coin, but haven't sold it (e.g. it's in cold storage, or it's <a href="https://blog.coinbase.com/update-on-bitcoin-cash-8a67a7e8dbdf">being held
hostage by Coinbase</a>). If we assume the "market cap over-valued factor" is a reasonable predictor of anything, then we can get an idea of how much unwanted Bitcoin Cash exists but hasn't been sold: the factor is 3.87, which means there exists about 3.87x more Bitcoin Cash than is actually being traded. Maybe. That would place the "alternative" market cap at $2.8 B, and the "alternative" price at $170. I think it's likely to slowly head towards those values as more people get coins out of cold storage, and if Coinbase let everybody have their BCC.</p>
<p><table border>
<tr><th>Coin</th><th>Quantity</th><th>Value</th></tr>
<tr><td>Litecoin</td><td>1.31</td><td>$103.11</td></tr>
<tr><td>Dash</td><td>0.22</td><td>$75.10</td></tr>
<tr><td>IOTA</td><td>88.8 M</td><td>$56.23</td></tr>
<tr><td>Dogecoin</td><td>44,800</td><td>$87.00</td></tr>
<tr><td>Monero</td><td>0.65</td><td>$78.03</td></tr>
<tr><td>USD</td><td>91.43</td><td>$91.43</td></tr>
<tr><td><b>Total</td><td>-</td><td>$490.90 (<span style="color:red">-1.8%</span>)</td></tr>
</table></p>
<p>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/google-trends-ripple.html</link>
   <guid>http://incoherency.co.uk/blog/stories/google-trends-ripple.html</guid>
   <pubDate>Thu, 07 Sep 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Google Trends portfolio: buying Monero</title>
   <description><![CDATA[Just a quick update on the Google Trends portfolio.]]></description>
   <content:encoded><![CDATA[<p>Just a quick update on the <a href="https://incoherency.co.uk/blog/stories/google-trends-cryptocurrencies.html">Google Trends portfolio</a>.</p>
<p><table border>
<tr><th>Coin</th><th>Google Trends score</th><th>Score relative to Bitcoin</th><th>Market cap</th><th>Market cap relative to Bitcoin</th><th>Market cap over-valued factor</th></tr></p>
<p><tr><td>Bitcoin</td><td>55 <small style="color:red">(-25)</small></td><td>1.00</td><td>$76,000,000,000 <small style="color:green">(+$4.3 B)</small></td><td>1.00</td><td>1.00</td></tr>
<tr><td>Ethereum</td><td>13 <small style="color:red">(-2)</small></td><td>0.24 <small style="color:green">(+0.04)</small></td><td>$35,700,000,000 <small style="color:green">(+$3.7 B)</small></td><td>0.47 <small style="color:green">(+0.02)</small></td><td>1.99 <small style="color:red">(-0.24)</small></td></tr>
<tr><td>Bitcoin Cash</td><td>2 <small style="color:red">(-6)</small></td><td>0.036 <small style="color:red">(-0.074)</small></td><td>$9,950,000,000 <small style="color:red">(-$250 M)</small></td><td>0.13 <small style="color:red">(-0.01)</small></td><td>3.47 <small style="color:green">(+2.13)</small></td></tr>
<tr><td>Ripple</td><td>10 <small style="color:red">(-4)</small></td><td>0.18 <small style="color:red">(-0.01)</small></td><td>$8,730,000,000 <small style="color:green">(+$910 M)</small></td><td>0.11 <small style="color:green">(+0)</small></td><td><b>0.63</b> <small style="color:green">(+0.05)</small></td></tr>
<tr><td>Litecoin</td><td>6 <small style="color:green">(+2)</small></td><td>0.11 <small style="color:green">(+0.057)</small></td><td>$3,380,000,000 <small style="color:green">(+$80 M)</small></td><td>0.044 <small style="color:red">(-0.002)</small></td><td><b>0.41</b> <small style="color:red">(-0.45)</small></td></tr>
<tr><td>Dash</td><td>5 <small style="color:green">(+0)</small></td><td>0.091 <small style="color:green">(+0.024)</small></td><td>$2,790,000,000 <small style="color:green">(+$60 M)</small></td><td>0.037 <small style="color:red">(-0.001)</small></td><td><b>0.40</b> <small style="color:red">(-0.17)</small></td></tr>
<tr><td>IOTA</td><td>3 <small style="color:red">(-1)</small></td><td>0.055 <small style="color:green">(+0.002)</small></td><td>$2,470,000,000 <small style="color:red">(-$80 M)</small></td><td>0.033 <small style="color:red">(-0.003)</small></td><td><b>0.60</b> <small style="color:red">(-0.07)</small></td></tr>
<tr><td>Monero</td><td>4 <small style="color:green">(+2)</small></td><td>0.072 <small style="color:green">(+0.045)</small></td><td>$2,100,000,000 <small style="color:green">(+$130 M)</small></td><td>0.028 <small style="color:green">(+0.001)</small></td><td><b>0.38</b> <small style="color:red">(-0.64)</small></td></tr>
<tr><td>Dogecoin</td><td>1 <small style="color:green">(+0)</small></td><td>0.018 <small style="color:green">(+0.005)</small></td><td>$231,000,000 <small style="color:green">(+$35 M)</small></td><td>0.0030 <small style="color:green">(+0.0003)</small></td><td><b>0.17</b> <small style="color:red">(-0.03)</small></td></tr>
</table></p>
<p>The major changes here are Bitcoin Cash's Trends score dropping by about 75% and Monero's score doubling. This now places Monero's "market cap over-valued factor" at substantially less than 1.00. Monero's Google Trends score actually went up on Tuesday night, but I put off
buying any because I wondered if it would quickly go down again.</p>
<p>The Google Trends scores seem highly volatile. On Sunday Bitcoin scored 75, on Tuesday night it scored 83, and now on Thursday morning it scores 55. This volatility could be a confounding variable in the performance of the portfolio.</p>
<p>Along similar lines, I realised Dogecoin perhaps shouldn't have been in the portfolio. I plugged the Google Trends score of 1 into the formula and got out a "market cap over-valued factor", but I have no way of knowing if the score of 1 is "just slightly more than 0, but enough to display as 1" or "almost enough to display as 2". If the score were 0 I wouldn't have bought it and I have no
way to know how much more than 0 it needs to be before it is displayed as 1. For that matter, I don't even know if the Google Trends score is linear in the number of searches. It could be a log scale for all I know, in which case my formula will over-value
the less popular cryptocurrencies.</p>
<p>On Sunday I said that the Bitcoin market cap might be over-valued by 6% or under-valued by 28% based on some dubious calculation. I
went on to say that's close enough that I'm not going to worry about it, and people asked why 28% is close enough not to worry
about. The answer is because it's 28% <i>under-valued</i>. Since I'm looking for things that are under-valued by comparing them to Bitcoin, I will
still pick things that are under-valued even if Bitcoin is under-valued. If the calculation said Bitcoin might be <i>over-valued</i>
by 28% then that would be more of a problem.</p>
<p>There was no cryptocurrency in the portfolio that is an obvious candidate to want to sell, so I just sold 1/6th of each of them
in order to buy the Monero.</p>
<p><table border>
<tr><th>Coin</th><th>Quantity</th><th>Value</th></tr>
<tr><td>Ripple</td><td>410</td><td>$93.14</td></tr>
<tr><td>Litecoin</td><td>1.31</td><td>$84.14</td></tr>
<tr><td>Dash</td><td>0.22</td><td>$81.27</td></tr>
<tr><td>IOTA</td><td>88.8 M</td><td>$78.24</td></tr>
<tr><td>Dogecoin</td><td>44,800</td><td>$93.86</td></tr>
<tr><td>Monero</td><td>0.65</td><td>$90.51</td></tr>
<tr><td><b>Total</td><td>-</td><td>$521.14 (<span style="color:green">+4.2%</span>)</td></tr>
</table></p>
<p>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/google-trends-monero.html</link>
   <guid>http://incoherency.co.uk/blog/stories/google-trends-monero.html</guid>
   <pubDate>Thu, 31 Aug 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Using Google Trends data to speculate on cryptocurrencies</title>
   <description><![CDATA[I did a little analysis this evening to try to find cryptocurrencies that are under-valued relative to Bitcoin, based
on Google Trends data, with the intention of buying whatever is under-valued and waiting for it to go up. I found
some possibilities and I spent some money.]]></description>
   <content:encoded><![CDATA[<p>I did a little analysis this evening to try to find cryptocurrencies that are under-valued relative to Bitcoin, based
on <a href="https://trends.google.com/trends/">Google Trends</a> data, with the intention of buying whatever is under-valued and waiting for it to go up. I found
some possibilities and I spent some money.</p>
<p><i>(Note: you may have seen a previous version of this article that said every cryptocurrency is over-valued relative to Bitcoin. My maths was wrong. I've
fixed it now. The difference was big enough that I actually spent some money, so this post is what that post should have been).</i></p>
<p><h3>Hypothesis</h3></p>
<p>The hypothesis here is that if the Google Trends score for (e.g.) "buy ethereum" is 50% of the score for "buy bitcoin" (i.e. about
50% as many people are looking to buy Ethereum as are looking to buy Bitcoin), then the Ethereum market cap should be
approximately 50% that of Bitcoin. If the market cap is too low then it is under-valued and I should buy some Ethereum.</p>
<p><h3>Data</h3></p>
<p>We're looking for cryptocurrencies with a "market cap over-valued factor" of less than 1, i.e. under-valued. Here's a table of my data:</p>
<p><table border>
<tr><th>Coin</th><th>Google Trends score</th><th>Score relative to Bitcoin</th><th>Market cap</th><th>Market cap relative to Bitcoin</th><th>Market cap over-valued factor</th></tr></p>
<p><tr><td>Bitcoin</td><td>75</td><td>1.00</td><td>$71,700,000,000</td><td>1.00</td><td>1.00</td></tr>
<tr><td>Ethereum</td><td>15</td><td>0.20</td><td>$32,000,000,000</td><td>0.45</td><td>2.23</td></tr>
<tr><td>Bitcoin Cash</td><td>8</td><td>0.11</td><td>$10,200,000,000</td><td>0.14</td><td>1.34</td></tr>
<tr><td>Ripple</td><td>14</td><td>0.19</td><td>$7,820,000,000</td><td>0.11</td><td><b>0.58</b></td></tr>
<tr><td>Litecoin</td><td>4</td><td>0.053</td><td>$3,300,000,000</td><td>0.046</td><td><b>0.86</b></td></tr>
<tr><td>Dash</td><td>5</td><td>0.067</td><td>$2,730,000,000</td><td>0.038</td><td><b>0.57</b></td></tr>
<tr><td>IOTA</td><td>4</td><td>0.053</td><td>$2,550,000,000</td><td>0.036</td><td><b>0.67</b></td></tr>
<tr><td>Monero</td><td>2</td><td>0.027</td><td>$1,970,000,000</td><td>0.027</td><td>1.02</td></tr>
<tr><td>Dogecoin</td><td>1</td><td>0.013</td><td>$196,000,000</td><td>0.0027</td><td><b>0.20</b></td></tr>
</table></p>
<p>(I excluded Ethereum Classic and ZCash because they scored 0 on Google Trends, which would mean the market cap is over-valued by a factor of infinity. Which might be
accurate... but this isn't the post for that kind of discussion).</p>
<p><h3>Analysis</h3></p>
<p>So the promising contenders here are Ripple, Litecoin, Dash, IOTA, and Dogecoin. With a factor of 1.02, Monero appears to be priced about right (as an aside:
at my previous employment I wrote a series of internal analyses in which I said Monero looked under-valued; it has since
increased by a factor of ~3 over the past month). Bitcoin Cash appears a little over-valued, and Ethereum appears to be heading
for a substantial drop.</p>
<p>Since this is all relative to Bitcoin, it doesn't give us a figure for how much Bitcoin might be over-valued. But we can get a rudimentary estimate by comparing
it to the average of the others: the mean "market cap over-valued factor" is 0.94,
which might suggest Bitcoin is over-valued by ~6%. Weighted by market cap, the average is 1.28, which might suggest Bitcoin is under-valued by ~28%. Both of
those are close enough to 1.00 that I'm not going to worry about it.</p>
<p>It is also quite possible that these "market cap over-valued factors" will correct towards 1.00 not by the price changing, but by the Google Trends scores changing. I'm
also not going to worry about that.</p>
<p><h3>Investment</h3></p>
<p>Just in case this analysis might work, let's allocate a small portfolio to it and see how it performs over the next couple of months. I don't actually have any faith at all in the
fundamental proposition of Ripple, Dash, or Dogecoin, and I have some doubts about IOTA. But I'm not here to talk about fundamentals, I'm here to talk about
Google Trends data, and I'm here to speculate, so we'll include them regardless.</p>
<p>I spent $100 on each of those cryptocurrencies, and, after trading fees, transaction fees, and unfavourable exchange rates, the portfolio looks like this:</p>
<p><table border>
<tr><th>Coin</th><th>Quantity</th><th>Value</th></tr>
<tr><td>Ripple</td><td>493</td><td>$99.61</td></tr>
<tr><td>Litecoin</td><td>1.58</td><td>$98.88</td></tr>
<tr><td>Dash</td><td>0.27</td><td>$99.01</td></tr>
<tr><td>IOTA</td><td>107 M</td><td>$98.44</td></tr>
<tr><td>Dogecoin</td><td>56,000</td><td>$99.68</td></tr>
<tr><td><b>Total</td><td>-</td><td>$495.62 (<span style="color:red">-0.9%</span>)</td></tr>
</table></p>
<p>If everything in this post is correct (a big if!), then we can expect each of those coins to increase in value such that the "market cap over-valued factor"
is 1.00. If that happened, and the relative Google Trends scores remained the same, then the portfolio would be up by ~120% (or ~50% if you don't count
Dogecoin). If it comes anywhere close to that, I'll be delighted.</p>
<p>I intend to post updates on this whenever there is anything interesting to say. Value goes up, value goes down, Google Trends scores change and I change
the coins in the portfolio, that sort of thing.</p>
<p>Also, for the avoidance of doubt: this post is not investment advice. Don't do as I do, don't do as I say, and don't complain when you lose all your money.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/google-trends-cryptocurrencies.html</link>
   <guid>http://incoherency.co.uk/blog/stories/google-trends-cryptocurrencies.html</guid>
   <pubDate>Sun, 27 Aug 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I tried to do the BLMRA 12 hour lawnmower race</title>
   <description><![CDATA[Earlier this year I bought a ride-on lawnmower to go lawnmower racing. I talked Feroz Salam
and James Nicholls into driving it with me, and Matt Game
and my Dad into helping in the pits, and we entered the BLMRA 12 hour endurance race.]]></description>
   <content:encoded><![CDATA[<p>Earlier this year I bought a ride-on lawnmower to go lawnmower racing. I talked <a href="https://projects.argh.in/">Feroz Salam</a>
and <a href="http://curbedambition.com/">James Nicholls</a> into driving it with me, and <a href="https://caconym.co.uk/">Matt Game</a>
and my Dad into helping in the pits, and we entered the BLMRA 12 hour endurance race.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1387"><img src="https://img.incoherency.co.uk/1387/thumb"></a></p>
<p>We modified the mower for racing over the course of a few months (removed blades, new engine, lights, number plates, padded seat, lowered centre of gravity, and
of course a snazzy paintjob),
although it turned out we hadn't done as much as most of the teams did. Most notably, we left the original lawnmower steering unchanged. Mainly due to
laziness, but also because we hadn't had any problems with it during testing.</p>
<p>Anyway we showed up at the circuit, and our pit was right next to Deadbull Racing who have this beautiful machine:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1534"><img src="https://img.incoherency.co.uk/1534/thumb"></a></p>
<p>They also had quite an impressive pit. Their setup was quite intimidating compared to ours, although they were very friendly towards us. We also met Les Pantry, one of the officials, shortly after we showed up. I told him I was concerned about scrutineering but he seemed to think
it would be fine.</p>
<p>Unbelievably, Les was right, and we passed scrutineering on the first try. The scrutineer complained that the track rod was bent, and that there were sharp edges on
the side impact plates. He passed us anyway but asked us to file the sharp edges down.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1529"><img src="https://img.incoherency.co.uk/1529/thumb"></a></p>
<p>The practice session went well. It was our first time driving the mower alongside other mowers, and everything seemed nice and safe.</p>
<p>I twisted my ankle in qualifying when my left foot fell off the side, but my stint went OK apart from that.
The qualifying session lasted 15 minutes longer than expected and Feroz
ended up doing a double stint, which culminated in the clutch breaking off and shredding the belt just after he crossed
the chequered flag. (It was lucky he did a double stint else it would have broken 15 minutes into the race).</p>
<p><a class="img" href="https://img.incoherency.co.uk/1536"><img src="https://img.incoherency.co.uk/1536/thumb"></a></p>
<p>Fortunately we had enough spare parts to repair this, and after a bit of grinding and welding, we had the mower ready again
with several hours to spare before the race.</p>
<p>On to the start grid. We qualified 27th (of 50! Not bad for a bunch of clowns on the worst mower in the field). When trying to find
our spot on the grid we had another run in with Les: "no, no, no, turn around, you guys will be much further back than this", he said, as we were pushing
the mower up towards 27th position. Les underestimated us.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1535"><img src="https://img.incoherency.co.uk/1535/thumb"></a></p>
<p>The start was intense. It was a Le Mans-style start, where the drivers line up opposite the mowers and then when the flag drops, everybody runs to
their mower, starts it up, and sets off. I ended up <a href="https://twitter.com/britclipuk/status/896468907904700417">15th into the first corner</a>! This was where our race peaked. The steering was getting
increasingly vague throughout my first stint, and the rack-and-pinion would occasionally skip some teeth. This is incredibly scary: your hands stay in the same place,
but all of a sudden you're veering off the track. You have to quickly realise what's happened and steer back to correct it.
Towards the end of my first stint the steering came disconnected completely and I couldn't carry on driving it.</p>
<p>We pushed the mower back to the pit and found that the bolts holding the steering rack
on had shaken loose. A minute later, we'd nipped them up, turned the wheel back and forth a couple of
times to make sure it was Nice and Safe, and sent James out for his first
stint.</p>
<p>Over the course of the next couple of hours
the ball-and-socket joint at the bottom of the steering column came loose and the steering
column would pull itself out of the socket, which would mean the steering became completely
disconnected until the driver pushed it back in. This resulted in Feroz rolling the mower and injuring his knee. (If you've never rolled a lawnmower
before, imagine rolling a car that has no seatbelt and no roof; it's quite unpleasant).</p>
<p><a class="img" href="https://img.incoherency.co.uk/1530"><img src="https://img.incoherency.co.uk/1530/thumb"></a></p>
<p>We pushed it back to the pit and welded the ball into the socket so that it couldn't come out
(the actual steering pivot is inside the ball, so the steering could still steer). This was a good
repair. The steering now felt rock solid and we were starting to build up some confidence. James
and I got in a couple more stints with no major issues.</p>
<p>In my final stint I was getting some speed up and getting confident bouncing over the bumps. I was overtaking a fair
amount of people. In my quest for ever-faster lines, I accidentally clipped the bales on the inside
of corners, a couple of times. Both times the (small) impact was accompanied with
a loud CLAAAANGGGG noise from the front end. It still drove OK so I didn't worry about it. Until
all of a sudden, as I was bombing along the pit straight at about 30mph, the mower
lurched to the right, just like it had done earlier on when the steering jumped some teeth. I
tried to steer left, but it made no difference. The mower smashed into a hay bale and I was thrown
off it, landing a few metres away on the next hay bale. The track rod had broken (although not in the
place that the scrutineer was concerned about), so the front wheels now pointed in random directions.</p>
<p>I couldn't push it on my own because the front wheels were pointing at random, and the pit crew
were apparently not paying any attention and were not coming to assist, so I abandoned the mower and walked back to the pit to
get some help. We dragged the mower across the track and down the pit lane until reaching
our pit, where we eventually decided that the steering we had was simply not safe enough to
race with. Even if we welded it back together (again), it's not up to the job and will only throw one of us into the bales (again). You can only take so many
violent accidents from the steering becoming disconnected before it's too scary to want to drive, so we decided to retire from the race, after about 5 hours.</p>
<p>Les came by and told us to get it welded and get back out there, but I don't think he'd have said that
if he'd have been driving it.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1538"><img src="https://img.incoherency.co.uk/1538/thumb"></a></p>
<p>So that's our story from this year's 12 hour. We're going to replace the steering
with something more appropriate and enter again next year, along with a few other improvements like further lowering the ride height
and centre of gravity, improving the lights, and putting something at the side of the seat
to stop us falling out.</p>
<p><small>(Photographs are taken by me, James Nicholls, Ian Clark, and Jason Ingold. I don't necessarily have the right to use all of them
so if you think I've used your photo unfairly please contact me and I'll sort it).</small>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/blmra-12-hour-2017.html</link>
   <guid>http://incoherency.co.uk/blog/stories/blmra-12-hour-2017.html</guid>
   <pubDate>Wed, 16 Aug 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I found a security vulnerability in SMS Privacy this morning</title>
   <description><![CDATA[I woke up this morning to find an email from my SMS Privacy server
informing me about an error:]]></description>
   <content:encoded><![CDATA[<p>I woke up this morning to find an email from my <a href="https://smsprivacy.org/">SMS Privacy</a> server
informing me about an error:</p>
<p><pre><code>[Mon Aug  7 06:05:09 2017] [error] Died at <i>[smsprivacy]</i> line 1341.</code></pre></p>
<p>(I have a script that emails me whenever the SMS Privacy web service reports any errors).</p>
<p>Worried that I might have to give somebody a refund (e.g. if it died halfway through handling a purchase), I
investigated further.  Line 1341 of the file in question just checks that the URL you're accessing is in
a list of valid possibilities, and dies otherwise. But it turned out to be in a code path that is only accessible
if you're authenticated as an admin. That's funny... I'm the only admin and I wasn't awake at 6am.</p>
<p>I looked in the nginx log and found that the request was to <tt>/admin/login.php</tt> (presumably from an automated
vulnerability scanner). That explains why it died: <tt>login.php</tt> isn't in the list of valid possibilities.</p>
<p>But why did that code even execute in the first place? Don't they have to authenticate as an admin first?</p>
<p><pre><code>my $admin = under('/admin' => sub {
    my ($c) = @_;
    if ($c->is_user_authenticated && $c->current_user->is_admin) {
        return 1;
    }
    $c->redirect_to('/login');
});
 
$admin->get('/' => sub { ... });
$admin->get('/foo' => sub { ... });
... <i>etc.</i> ...</code></pre></p>
<p>This is the code that checks whether a user is an admin. <tt>under()</tt> is a <a href="http://mojolicious.org/">Mojolicious</a>
function that allows you to restrict access to certain URLs "under" a parent URL. In this case, we're restricting access to
URLs beginning <tt>/admin</tt>.</p>
<p>You'll note that the function returns 1 if the user is authenticated as an admin, and redirects to <tt>/login</tt> otherwise.
Unfortunately, <tt>$c->redirect_to</tt> returns a true value, and in Perl a function implicitly returns the value of its last
statement. I knew all of these things, I had just failed to put them together.</p>
<p>If you're not an admin, it would write a redirect response to the socket, followed by the actual content that an admin
would see. The upshot of this is that <b>it always allows
any user to view the content in the admin area!</b> Shit.</p>
<p>Upon figuring out what the vulnerability was, I immediately fixed it (add a "<tt>return 0</tt>" after the redirect), and then tried to work out whether it had been exploited.</p>
<p>The index page of the admin area gives revenue statistics. It also has hyperlinks to pages listing information about user
accounts, Bitcoin payments, and user survey responses. None of the pages can show phone numbers or message contents. Passwords are
hashed and salted using <a href="http://search.cpan.org/~arodland/Crypt-PBKDF2-0.101170/lib/Crypt/PBKDF2.pm">Crypt::PBKDF2</a>,
but the hashes are not shown anywhere in the admin area. None of the pages can modify any information.</p>
<p>I only had logs for the past 10 days, but I saw logs of people accessing the admin index page,
although I don't know whether they actually knew how to read the responses, or whether they
were just running automated scanners that threw the results away. In any case, the best they got was revenue statistics. I didn't
see any logs of people accessing the pages that contain more sensitive information.</p>
<p>So at this point I knew it was possible that people had seen some sensitive user information, although there is no proof that they did.
I quickly wrote up a disclosure for users and <a href="https://smsprivacy.org/info-leak">published it on the SMS Privacy website</a> (read it if you're interested). I
also resolved to get the site professionally security tested and to publish the results. I have now found somebody to do the testing.</p>
<p>I wasn't sure whether writing the disclosure was a good move or not. It's certainly the <i>right</i> thing to do, but is it a profitable thing to do?
As far as I know, nobody else in the world knew about this vulnerability.
I could have just silently fixed it and probably nobody would be any the wiser. Even if somebody <i>was</i> exploiting it, they'd be unlikely
to admit to it, so I'd probably get away with it. However, the SMS Privacy customer base skews very strongly towards the tech-savvy side of
the spectrum, so I think they'll understand that admitting that the vulnerability existed is a good thing rather than a bad thing. I've
not received any hate mail so far, at any rate.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/smsprivacy-info-leak.html</link>
   <guid>http://incoherency.co.uk/blog/stories/smsprivacy-info-leak.html</guid>
   <pubDate>Mon, 07 Aug 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The only time Hacker News is this interested in Bitcoin is when there's a bubble forming</title>
   <description><![CDATA[You might have got the impression that there are a lot of Bitcoin-related posts on Hacker News lately.
With SegWit set to activate in the next few weeks, and Bitcoin Cash likely to fork
off on the 1st of August, I took a look at Hacker News' relationship
with Bitcoin over the past years.]]></description>
   <content:encoded><![CDATA[<p>You might have got the impression that there are a lot of Bitcoin-related posts on <a href="https://news.ycombinator.com/">Hacker News</a> lately.
With SegWit set to activate in the next few weeks, and Bitcoin Cash likely to fork
off on the 1st of August, I took a look at Hacker News' relationship
with Bitcoin over the past years.</p>
<p>In this post I'm going to argue, based on historical trends of Bitcoin-related posts on Hacker News, that there is a Bitcoin bubble coming in the next few months.</p>
<p>(Take this with a pinch of salt. Humans are
good at seeing patterns where there are none. Don't trade on this information.
Don't blame me if you lose money. Don't say I didn't warn you.)</p>
<p>I used <a href="https://hn.algolia.com/">Algolia's HN Search API</a> to collect the HN data,
and the <a href="https://99bitcoins.com/price-chart-history/">99Bitcoins historical price chart</a>
to get Bitcoin price data.</p>
<p><h3>How many Bitcoin-related posts are on HN each month?</h3></p>
<p>I used Algolia to find all of the posts matching "bitcoin" going back as far as possible.
This turned out to be far too much to look through, so I restricted my search to only those
posts that had more than 20 upvotes.</p>
<p>I used URLs like this:</p>
<p><tt>http://hn.algolia.com/api/v1/search_by_date?query=bitcoin&tags=story&numericFilters=points&gt;20</tt></p>
<p>And here's a chart showing the results:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1523"><img src="https://img.incoherency.co.uk/1523/thumb"></a></p>
<p>The <i>x</i> axis is time, grouped by month. The <i>y</i> axis is number of posts on Hacker News that match the search term "bitcoin" and have more than 20 votes.</p>
<p>(2010 has a few months missing, so the <i>x</i> axis is not quite linear in time. This is because some months had 0 results and my spreadsheet-fu is weak. I'm sorry.)</p>
<p>Notice the big uptick in Bitcoin interest on Hacker News this month, and compare to historical events.</p>
<p><h3>What were the peaks, and what happened next?</h3></p>
<p>As you might expect, the peaks in Bitcoin-related posts on HN correspond roughly to peaks in the Bitcoin price. What's interesting
is that the number of Bitcoin-related posts for this July (the current month) looks very similar to what happens
during a Bitcoin bubble.</p>
<p>There are 4 periods to pay attention to:</p>
<p>The <b>June 2011</b> peak in Bitcoin-related Hacker News posts (~40 posts) represented the peak of the bubble, and the
following month saw the Bitcoin price decline by about 20% ($16 to $13), with a decline in HN posts.</p>
<p>In <b>March 2013</b>, there was once again a jump up to ~40 Bitcoin-related posts, and the following month saw the
Bitcoin price increase by about 45% ($96 to $140), along with an increase in HN posts.</p>
<p>In <b>October 2013</b>, there was once again a jump up to ~40 Bitcoin-related posts, and the following month saw the Bitcoin
price increase by about 450% ($200 to $1100), along with an increase in HN posts.</p>
<p>In <b>July 2017</b>, there was <i>once again</i> a jump up to ~40 Bitcoin-related posts. What will next month see?</p>
<p><h3>What happened immediately prior to those months?</h3></p>
<p>Are we at the peak of a June 2011-style uptick in Bitcoin interest on HN, or are we just at the beginning of
a 2013-style uptick in Bitcoin interest? Let's take a look at what happened before.</p>
<p>In May 2011, the Bitcoin price had increased by about a factor of 3 ($3 to $9), so it's likely that the subsequent June 2011 Bitcoin interest
on HN was a reaction to that. There was a bubble peak during June 2011.</p>
<p>In February 2013, the Bitcoin price had increased by 50% ($20 to $30), and during March 2013 the price
increased by another factor of 3 ($30 to $90), followed by a ~45% increase the following month.</p>
<p>In September 2013, there was a negligible (~3%) drop in Bitcoin price ($137 to $133), and during October 2013 the price
increased from $133 to $200 (~50%), followed by the much <i>much</i> larger increase in the following month (450%).</p>
<p>In June 2017, there was a negligible (~4%) increase in Bitcoin price ($2400 to $2500), and during July 2017 the price
increased from $2500 to $2700 (~8%).</p>
<p><h3>What's going to happen next?</h3></p>
<p>We can try to guess what will happen over the next months by looking at what happened in the past under similar conditions. There are 3 candidate scenarios:</p>
<p><b>June 2011:</b> price had already gone up 3x the previous month, bubble peaked in this month, and price declined slightly the following month.</p>
<p><b>March 2013:</b> price had already gone up a lot the previous month, increased 3x during this month, and went up a lot (and peaked) the next month.</p>
<p><b>October 2013:</b> price hadn't done very much the previous month, increased a lot during this month, and went up 4.5x, to the bubble's peak, at the end of the next month.</p>
<p>Now, in <b>July 2017</b>, the price hasn't gone up very much last month, and also hasn't gone up very much this month.</p>
<p> In June 2011 the uptick coincided with the bubble peak.
In March 2013 the uptick preceded the bubble peak by 1 month. In October 2013 the uptick preceded the bubble peak by 1-2 months (the peak was on
the very last day of November). So it looks like <b>Bitcoin interest on HN could be a leading indicator of bubbles</b>.</p>
<p>If this trend continues, we can expect a Bitcoin bubble to peak in 2-3 months' time, at a large-ish multiple of the current price (maybe about $10,000?).</p>
<p>Looking at the price charts, one might argue that we've <i>just seen</i> the peak of a bubble:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1524"><img src="https://img.incoherency.co.uk/1524/thumb"></a></p>
<p>But if we overlay the price on the HN posts graph, we see that historically the uptick in HN posts has coincided with a price <i>increase</i>, but has
<i>preceded the peak</i> of the bubble:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1525"><img src="https://img.incoherency.co.uk/1525/thumb"></a></p>
<p><h3>What falsifiable predictions can we make?</h3></p>
<p>All this is fine and dandy, but what can we actually predict?</p>
<p><h4>1. In August, we'll see substantially more than 40 Bitcoin-related posts on HN with over 20 votes.</h4></p>
<p>If this doesn't happen, then history is not repeating itself and the other predictions are likely to be wrong.</p>
<p><h4>2. A Bitcoin bubble will peak before the end of the year.</h4></p>
<p>If prediction 1 is correct, then there is once again rapidly-increasing interest in Bitcoin among the Hacker News community. If this
corresponds to increased interest among the wider population, then there will probably be lots of people buying Bitcoin for the first time,
with all of the associated enthusiasm and greed. The perfect ingredients for a bubble.</p>
<p><h4>3. The Bitcoin price will pass $5,000 before December.</h4></p>
<p>It wouldn't be much of a bubble if it didn't increase the price by a factor of several. If prediction 2 is correct, I think $5,000 is quite a conservative bet.
I don't know if I actually <i>believe</i> this prediction, but it follows from what we've seen so far.</p>
<p><h3>Conclusion</h3></p>
<p>If the Bitcoin-related posts on HN have any predictive power, we can expect exciting things from Bitcoin in the coming months. I will
certainly be following up a few months from now to see what happened. My "gut feeling" is that $5,000 within 3 months is obviously just
wishful thinking. But there has undeniably been an uptick in Bitcoin interest on Hacker News, and historically the only times we've
seen HN this interested in Bitcoin is when there's a bubble forming.</p>
<p>The Algolia HN API is really useful for this sort of analysis. It's well-documented and relatively easy to use. While playing around with the data,
I also came across the following posts:</p>
<p>In May 2009, the first time Bitcoin is ever posted to HN: <a href="https://news.ycombinator.com/item?id=599852">Bitcoin: peer-to-peer network based anonymous digital currency</a>.
Only 5 votes, and 3 comments. "An exceptionally cute idea, but there is absolutely no way that anyone is going to have any faith in this currency".</p>
<p>In June 2011, one third of the posts were predicting the death of Bitcoin. Examples include <a href="https://news.ycombinator.com/item?id=2628989">Why Bitcoin Will Fail As A Currency</a>. A lot of the comments do a good job of debunking the article, but there is still a general undercurrent of uncertainty about whether it's even legal
to use Bitcoin. Fears that governments could stamp it out with the flick of a legislatory pen. One Tulip reference.</p>
<p>In March 2013, <a href="https://news.ycombinator.com/item?id=5335248">Bitcoin drops 10USD in less than 4 hours</a>, followed 1 hour later by <a href="https://news.ycombinator.com/item?id=5335601">Bitcoin goes up $10 in just one hour</a>. People talking about how nobody prices anything in Bitcoin. A rather prescient "Hey, who knows. Maybe my 4 BTC will be worth $1000s in a few years". A bold prediction, "1 BTC under $15 within 60 days", was way off the mark. Since that comment was made, Bitcoin has never been below $70. Someone complains that "$40+ per BTC is VASTLY overpriced". Lots of talk of bubbles. Another Tulip reference.</p>
<p>In October 2013, <a href="https://news.ycombinator.com/item?id=2613271">Safari extension to hide Bitcoin stories on HN</a>. Someone got sick of hearing about Bitcoin. To be fair, October 2013 was peak-Bitcoin for HN, with 118 posts getting more than 20 votes. That's like 4 per day! Somebody else patched the extension <a href="https://news.ycombinator.com/item?id=2615535">to hide stories about hiding stories</a>.</p>
<p>At first almost nobody cared about Bitcoin, then
they were skeptical about its legality, or that it was actually worth any "real" money. Nowadays nobody is
credibly arguing about these things, and it's mostly moved on to
discussion about the technology. People are starting to take Bitcoin seriously.</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/hacker-news-bitcoin.html</link>
   <guid>http://incoherency.co.uk/blog/stories/hacker-news-bitcoin.html</guid>
   <pubDate>Sun, 30 Jul 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>BTC-e, Alexander Vinnik, and the missing MtGox Bitcoins</title>
   <description><![CDATA[
Q: How do you launder the Bitcoins you stole from MtGox?
A: Set up your own exchange and sell them on there]]></description>
   <content:encoded><![CDATA[<p>
<blockquote><i><b>Q:</b> How do you launder the Bitcoins you stole from MtGox?<br>
<b>A:</b> Set up your own exchange and sell them on there</i></blockquote></p>
<p>A Russian chap named Alexander Vinnik was <a href="http://www.reuters.com/article/us-greece-russia-arrest-idUSKBN1AB1OP">arrested in Greece today</a>
on suspicion of "running a $4 billion Bitcoin-laundering ring".</p>
<p>BTC-e is a Bitcoin exchange run anonymously that has been down for a couple
of days. I'm not sure if it has been taken down by the authorities or not.</p>
<p>But it turns out Alexander Vinnik is the person (or at least, one of the
people) behind BTC-e. It also turns out that the BTC-e wallet contains a
huge amount of Bitcoin that was stolen from MtGox a few years ago, and
some of it "seems to have moved straight to internal storage rather than
customer deposit addresses".</p>
<p>There's a good writeup by WizSec (who you may recognise from their previous investigation into the MtGox theft and the Willy bot) with more
in-depth analysis,
worth a read: <a href="http://blog.wizsec.jp/2017/07/breaking-open-mtgox-1.html">http://blog.wizsec.jp/2017/07/breaking-open-mtgox-1.html</a>.</p>
<p>Anyway it looks like this guy Vinnik hacked MtGox, stole a load of their money, and
then had to work out how to launder it. His method was to setup a rival
exchange and sell the BTC on his own exchange. You don't have to satisfy anybody's
anti-money laundering requirements if you run the exchange! He then just
sells the stolen BTC to unsuspecting BTC-e customers and walks away with
clean money.</p>
<p>Quite a fascinating story.</p>
<p>At minimum, it currently looks like Vinnik is likely to have at least been <i>in on</i> the laundering
of the MtGox Bitcoin, even if he didn't actually steal it himself. Although it is, of course, possible
that he's been framed by somebody else involved with BTC-e.</p>
<p>It's still not clear whether BTC-e was taken down by the authorities, or whether authorities
have taken the money. If so, I hope they give innocent customers of
BTC-e all of their money back, but <a href="https://incoherency.co.uk/blog/stories/dark-net-market.html">I'm not holding my breath</a>.</p>
<p>Fascinating story anyway.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/btce.html</link>
   <guid>http://incoherency.co.uk/blog/stories/btce.html</guid>
   <pubDate>Wed, 26 Jul 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I tried to buy a thing off a dark net market, and the FBI stole my money</title>
   <description><![CDATA[I'm interested in online privacy and freedom, and I've wanted to make a purchase on a dark net market for quite a while.
On the 26th of June I took the plunge. I'd heard AlphaBay was
a popular market so (for the full experience) I loaded up Tails Linux in a virtual
machine and navigated to the AlphaBay site.]]></description>
   <content:encoded><![CDATA[<p>I'm interested in online privacy and freedom, and I've wanted to make a purchase on a dark net market for quite a while.
On the 26th of June I took the plunge. I'd heard AlphaBay was
a popular market so (for the full experience) I loaded up <a href="https://tails.boum.org/">Tails Linux</a> in a virtual
machine and navigated to the AlphaBay site.</p>
<p><h3>AlphaBay Review</h3></p>
<p>The site was quite lame. I'm amazed it was so popular. It seemed to be a very basic CMS that had some
marketplace functionality shoe-horned in. No problem though.</p>
<p>I spent some time searching around for something that didn't seem too illegal. At first I was tempted by some gold bars
that were available, but they seemed awfully cheap. I eventually realised they were selling <i>fake</i> gold bars!
Presumably the scam is that people buy them on purpose, and then pass them off as legitimate gold bars, and pocket the
difference.</p>
<p>Almost everything on the site is illegal, as you might expect, but I eventually found some "physical Bitcoins" on offer, and I ordered one
for about &pound;14. I'm quite sure it didn't actually have any Bitcoin loaded on it, it's probably just a pretty-looking coin,
but that's fine. It should be an interesting experience nonetheless.</p>
<p>The AlphaBay user experience around payments is really bad. Instead of simply paying for your order, you need to deposit
money into your AlphaBay account, except it doesn't tell you exactly how much to deposit. And since items are priced in USD and
the exchange rate constantly changes, your exact-amount deposit might not be enough by the time you are actually able to purchase the item. So
I ended up paying quite a bit over the actual amount.</p>
<p>The site didn't seem to have any way to display incoming unconfirmed payments, which made me a little nervous that my payment
was never going to show up. (I don't understand why people do this: if you have the capability to process Bitcoin payments, you
have the capability to detect unconfirmed Bitcoin payments, so why not just display them and put your users' minds at ease? It just
smacks of amateur-hour). But
the payment eventually showed up.</p>
<p>There is an order queuing feature that is supposed to automatically place the order as soon as your Bitcoin payment gets confirmed,
but it did not work. I had to place the order again, manually, and cancel the queued order.</p>
<p><h3>AlphaBay Takedown</h3></p>
<p>This post was originally just going to be a review of AlphaBay, after my physical Bitcoins arrived. But they never arrived.</p>
<p>On the 4th of July, AlphaBay was <a href="http://www.bbc.com/news/technology-40670010">shut
down by an international effort led by the FBI, the US DEA, and the Dutch National Police</a>.</p>
<p><h3>Ethics</h3></p>
<p>Everybody selling on AlphaBay was doing so because they voluntarily decided to, and everybody
buying on AlphaBay was doing so because they voluntarily decided to. Nobody was being forced to use the site.
And while it is obviously <i>illegal</i> to facilitate the trade of illegal drugs, I don't think it's <i>unethical</i> to do so,
and I can't otherwise see anything at all unethical about the operation of the site. Anybody who doesn't want to
use the site is free to avoid using it.</p>
<p>Even if you think it is unethical to do illegal things, not everything on the site was illegal (e.g. physical Bitcoins). And even some of the things that are
illegal in some jurisdictions are not illegal in all jurisdictions (e.g. marijuana). Is it unethical to do legal things on the same website
as other people are doing illegal things? I don't think so.</p>
<p>Not all of the AlphaBay usage was illegal, and not all of the AlphaBay usage was unethical. There was a non-zero amount
of perfectly legal and ethical trading going on (e.g. me trying to buy some physical Bitcoins).
And there's certainly a very compelling case that <i>none</i> of the AlphaBay usage was unethical, because everybody
trading there was doing so voluntarily.</p>
<p>The only involuntary transaction that any AlphaBay users were involved in was the theft of their Bitcoins by the FBI.</p>
<p>So I ask: who has acted unethically here? Is it the people running a marketplace where anybody can trade anything with
anybody else, or is it the people shutting down the marketplace and stealing innocent people's money?
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/dark-net-market.html</link>
   <guid>http://incoherency.co.uk/blog/stories/dark-net-market.html</guid>
   <pubDate>Tue, 25 Jul 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Why Bitcoin has to succeed</title>
   <description><![CDATA[Some people want to transition to a cashless society. If that happens (and governments, at least, appear
very keen to make that happen), we'll all be left with no way to pay each other without going
through a third party payments company (banks, Visa, PayPal, etc.). This means people have no way to pay each other without
asking permission from such a company, and being subject
to censorship and surveillance at best, and the risk of the funds being stolen at worst.]]></description>
   <content:encoded><![CDATA[<p>Some people want to transition to a cashless society. If that happens (and governments, at least, appear
very keen to make that happen), we'll all be left with no way to pay each other without going
through a third party payments company (banks, Visa, PayPal, etc.). This means people have no way to pay each other without
asking permission from such a company, and being subject
to censorship and surveillance at best, and the risk of the funds being stolen at worst.</p>
<p>Already, businesses in the UK that accept cash payments worth over &euro;10,000 <a href="https://www.gov.uk/guidance/money-laundering-regulations-high-value-dealer-registration">must register
with HMRC as a "high-value dealer"</a>. In France, <a href="http://www.financialsense.com/contributors/michael-shedlock/france-limits-cash-restrictions-gold">it
is illegal to perform a cash transaction over &euro;1,000</a> (yes, <b>one</b> thousand). And <a href="https://www.stripes.com/news/italy-transactions-exceeding-1-000-euros-must-be-electronic-1.165892">the same is true in Italy</a>. Last year, the Indian government <a href="http://www.hindustantimes.com/india-news/rs-1000-and-500-notes-become-history-in-pm-modi-s-war-on-black-money/story-fIWdjMm3yVMrbN04rI8jPO.html">declared all 500Rs and 1000Rs banknotes no longer legal tender</a>, and with only 4 hours notice.</p>
<p>Just this week, a <a href="http://www.bbc.com/news/business-40561807">British government report on the gig economy</a>
suggested that "cash payments should be phased-out".</p>
<p>This "war on cash" will be (indeed, is already being!) presented as if it's supposed to stop bad people from doing bad things. But criminals will come up
with something. Perhaps they'll give each other weapons, ammunition, favours, or something else, but they'll
carry on doing what they're doing and they'll find some way to transfer value, albeit less efficiently.</p>
<p>It's ordinary law-abiding people who will be hit the hardest. To avoid such a disaster and retain our financial freedom, we have to
have access to a permissionless, trustless, censorship-resistant, surveillance-resistant payments system. Bitcoin has to succeed.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/bitcoin-must-succeed.html</link>
   <guid>http://incoherency.co.uk/blog/stories/bitcoin-must-succeed.html</guid>
   <pubDate>Tue, 11 Jul 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Double-check Bitcoin addresses when pasting (Bitcoin TX Generator malware)</title>
   <description><![CDATA[Back in April I wrote about the Large Bitcoin Collider and how
it is probably malware. Well, now there's another (even more blatant) piece of malware being spread via reddit.]]></description>
   <content:encoded><![CDATA[<p>Back in April I wrote about the Large Bitcoin Collider and <a href="stories/large-bitcoin-collider.html">how
it is probably malware</a>. Well, now there's another (even more blatant) piece of malware <a href="https://web.archive.org/web/20170709204545/https://www.reddit.com/r/BitcoinMarkets/comments/6m8yni/when_trading_howsoever_always_wait_for/">being spread via reddit</a>.</p>
<p><h3>The post</h3></p>
<p><a href="https://www.reddit.com/user/daisypiggy">/u/daisypiggy</a> (appears to be a bought account: high karma but no posting history) wrote a post
on r/BitcoinMarkets about how it is important to wait for at least 1 confirmation when receiving Bitcoin transactions because "new software is
being developed to scam you". Supposedly
this new piece of software generates a Bitcoin transaction that looks valid, and will show up on the victim's wallet as an unconfirmed incoming
transaction, but which will eventually disappear.
Included in the post was a <a href="https://github.com/chester7/txgen">helpful link to a github repo containing the software.</a></p>
<p><a href="https://www.reddit.com/user/Frakk4d">/u/Frakk4d</a> promptly wrote a response about how the software works:</p>
<p><blockquote>I've seen this software before. It doesn't actually work, just "crashes" on launch then lurks in the background waiting for you to copy a BTC/eth address. When you do, it swaps it for their own so you end up sending your coins to them.</blockquote></p>
<p>So it seems the post is intended to trick would-be scammers into downloading the software, rather than to warn legitimate users about
a new attack.</p>
<p><h3>The software</h3></p>
<p>I had a quick look and wrote up a response:</p>
<p><blockquote><p>I checked out the source in the git repo, and the binary release, and there is absolutely no way the binary was generated using the source in the repo.</p>
<p>The binary release is launched via some .bat files, which are neither present nor generated by the Makefile in the repo.</p>
<p>The .bat files execute a file at includes/APIs/cvsrvc32.exe which is neither present nor generated by the Makefile in the repo.</p>
<p>The includes/APIs/ directory also contains a bunch of syntax highlighting configuration files (for no apparent reason) which are neither present nor generated by the Makefile in the repo.</p></blockquote></p>
<p>But the real smoking gun is what I found in <tt>cvsrvc32.exe</tt>:</p>
<p><pre><code>$ strings cvsrvc32.exe | egrep ^.1
[... a few lines redacted ...]
$1f8=1f8f7jwgPTszFyUaCTcFuPbXxVD5LAVx
$1Ci=1CiuQujVPphnVhCmQ5jdqAtFuAbxrsco
$1bZ=1bZa1az6eV23z6DacS6N2ZP9wMyFrwBv
$1RY=1RYcbV1CH8urKk1U8A5S3w181tNf3XkZ
$1vK=1vKn17CbgwW8vTCqkCqkUUj24thqNGEb
$1xc=1xcMCqSm11NxA9SCF7U4Wtf8xXCJxH8f
$1AM=1AMpfNMHS8EA3vrp3f4rd4gSmfEh3Cay
$1Zm=1ZmkrC2ddGi1YNMCmtFNyWgsF5BLDurM
$1ZZ=1ZZ9uR5sULaF3d6tc9zBNvz5uQJ7bCbi
$1AU=1AUekY2ViydicrKf9v5JrnRaZUiGHhPM
[... lots more ...]</code></pre></p>
<p>(full output at <a href="https://pastebin.com/yTWzhqTU">https://pastebin.com/yTWzhqTU</a>).</p>
<p>This is a mapping of 3-character prefixes to full Bitcoin addresses!</p>
<p><h3>The malware</h3></p>
<p>Combined with Frakk4d's information, we can surmise how the software works without bothering to disassemble it:</p>
<p><ul>
<li>It crashes at launch so the user thinks it just didn't work, and launches its payload (possibly also installing its payload as a rootkit, or run-at-startup, or similar)</li>
<li>When anything is copied to the clipboard it scans for a Bitcoin address</li>
<li>If it finds a Bitcoin address, it replaces it with one controlled by the attacker that shares the same first 3 characters</li>
</ul></p>
<p>This is particularly interesting because although it is obvious that a Bitcoin address <i>could</i> be substituted with one that shares a short prefix, I hadn't yet come
across any evidence that there is malware in-the-wild actually doing this attack.</p>
<p>I haven't worked out a convenient way to check all 3248 addresses to see if they have any transaction history, but I think it would be interesting to do so. I'll try and do it tomorrow.</p>
<p><h3>Lessons to learn</h3></p>
<p><ol>
<li>Don't run random code you find online, especially if it's related to Bitcoin, and <i>especially</i> if it's related to scamming.</li>
<li>When pasting a Bitcoin address, double-check as much as possible, not just a few characters at the start.</li>
</ol></p>
<p><h3>Any other business</h3></p>
<p>Although this example only replaces 3-character prefixes (and, really, only 2-character prefixes), it is not too hard to imagine a similar piece of malware that replaces longer prefixes. <a href="https://github.com/samr7/vanitygen">Vanitygen</a> can generate nearly 50 Million addresses per second on an old-ish machine, so it shouldn't take too long to pre-generate an address for all possible 4-, 5-, or even 6-character prefixes. Expect to see this in the future.</p>
<p>Another interesting point is that only 3248 substitutions exist in the executable. Bitcoin addresses are encoded with base58, so in theory there should be 58<sup>2</sup> possibilities = 3364 address prefixes. I'm not sure whether the remaining prefixes can simply never exist, or whether this malware accidentally misses ~3% of possible prefixes. (If you know, let me know!).</p>
<p>And, in case you want to do some more analysis of the executable, I've pinned the ZIP file I downloaded from the Github repo "Releases" page in <a href="https://ipfs.io/">IPFS</a> at <a href="https://ipfs.io/ipfs/QmdteaeZ7JmQ6U8aiRFPzKWdBNfSTYojsPeUurK1nm8XVx/BitTXGenerator-Win-x86-x64-1.2.7.zip">/ipfs/QmdteaeZ7JmQ6U8aiRFPzKWdBNfSTYojsPeUurK1nm8XVx/BitTXGenerator-Win-x86-x64-1.2.7.zip</a> (don't run it, for obvious reasons).</p>
<p><h3>Updates (2017-07-10)</h3></p>
<p>Frakk4d has found evidence that the "daisypiggy" account has been perpetrating this scam for quite some time: <a href="https://imgur.com/a/p3HLN">https://imgur.com/a/p3HLN</a>.</p>
<p>The executable contains 3249 P2SH addresses in addition to the 3248 P2PKH ones: <a href="https://pastebin.com/bpiKawY1">https://pastebin.com/bpiKawY1</a>.</p>
<p>The executable actually contains at least 185190 addresses for various cryptocurrencies, including the Bitcoin ones: <a href="https://ipfs.io/ipfs/QmYfbYNQzDxKz692ergwoxyeDyK2iTCu8CNneD2VWN4rnv/addresses.txt">/ipfs/QmYfbYNQzDxKz692ergwoxyeDyK2iTCu8CNneD2VWN4rnv/addresses.txt</a>.</p>
<p>And the plot thickens further: none of the Bitcoin addresses I checked actually have valid checksums. I'm guessing the program computes the correct checksum and substitutes it accordingly. I'm running out of inclination to look into this any further, but if you come up with anything interesting, please let me know and I'll update this post.</p>
<p><h3>Update 2017-11-29</h3></p>
<p><a href="https://www.grahamedgecombe.com/">Graham</a> points out that all of the addresses in the file are in fact Bitcoin addresses, they're just missing the "1" prefix! And that if you add a "1" prefix, the checksum computes correctly. So that's that mystery solved. He also checked the total payments to those addresses and found that they came to 3.7 BTC (which, at today's insane prices, would be about &pound;30,000).</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/bitcoin-txgen-malware.html</link>
   <guid>http://incoherency.co.uk/blog/stories/bitcoin-txgen-malware.html</guid>
   <pubDate>Sun, 09 Jul 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to create 3d-printed stencils for spray-painting</title>
   <description><![CDATA[I wanted to make some custom spray-painting stencils. I've done it before by printing on paper
and cutting out the shapes, but found it to be laborious and time-consuming. Also the stencils don't last for more than
a couple of uses before the paper gets too soggy.]]></description>
   <content:encoded><![CDATA[<p>I wanted to make some custom spray-painting stencils. I've done it before by printing on paper
and cutting out the shapes, but found it to be laborious and time-consuming. Also the stencils don't last for more than
a couple of uses before the paper gets too soggy.</p>
<p>But <a href="https://incoherency.co.uk/blog/stories/3d-printer.html">I have a 3d printer</a>, so I ought to be able to do better.</p>
<p>I couldn't work out how to use <a href="https://www.freecadweb.org/">FreeCAD</a> to do this,
and I'm not familiar enough with any other CAD software. (I think it should be possible to do
this natively in <a href="http://www.openscad.org/">OpenSCAD</a>, which might be a better way to go
as it'll generate more well-optimised meshes).</p>
<p>Anyway, the <a href="https://en.wikipedia.org/wiki/STL_%28file_format%29">STL file format</a>
is quite simple, so I wrote a <a href="https://gist.github.com/jes/285fb480fe91ee9b18016e7e4194c07d">short perl script</a>
to read in a PNG image and output a triangle
mesh which I could then load straight into <a href="http://slic3r.org/">Slic3r</a> to send to the
3d printer.</p>
<p>There is quite an elegant algorithm to convert the black-and-white image into a triangle mesh. You just need to iterate over
every pixel in the input image and:</p>
<p><ul>
<li>if it's black, insert a square face above and below the pixel</li>
<li>if it's a different colour to its left neighbour, insert a square face to the left of the pixel</li>
<li>if it's a different colour to its top neighbour, insert a square face to the top of the pixel</li>
</ul></p>
<p>A "square face" is just 2 triangles, because STL only supports triangles. You'll note that large flat square areas end up with thousands of triangles
where only 2 are necessary. This causes large file sizes and slow loading times in the slicer.
I have a few ideas for optimising the mesh, but hopefully I can find an existing program to do it for me. I've not looked yet.</p>
<p>(The script is quite unfinished and not suitable for use, but might be a good starting point if you intend to
do something similar. It needs to take options via CLI instead of hard-coded, and it ought to optimise the mesh
a bit. It would also benefit from outputting the binary STL format instead of the text version.)</p>
<p>I downloaded a Bitcoin symbol image from a page on <a href="https://en.bitcoin.it/wiki/Promotional_graphics">the Bitcoin.it wiki</a>:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1505"><img src="https://img.incoherency.co.uk/1505/thumb"></a></p>
<p>and modified it to be black-and-white and keep the centres of the B's attached:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1506"><img src="https://img.incoherency.co.uk/1506/thumb"></a></p>
<p>I then ran my perl script and loaded the STL file in Slic3r:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1507"><img src="https://img.incoherency.co.uk/1507/thumb"></a></p>
<p>(Although I didn't notice at the time, my script actually generated the model upside down by assuming (0,0) is at top-left instead of bottom-left. Not a problem though,
you can just flip the stencil over.)</p>
<p>The stencil is 10cm by 10cm by 3mm, and took about 45 minutes to print on my printer.</p>
<p>Size is the biggest limitation of this
method. The print bed on my printer is 20cm by 20cm, with a usable area a few cm under that. If you don't want overspray,
and you don't want to have to mask around the edges of the stencil, you also need a good
margin of stencil material around the shape itself, leaving you with a practical image size of not much more than 10cm by 10cm.</p>
<p>Here's the finished stencil, next to a test spray:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1502"><img src="https://img.incoherency.co.uk/1502/thumb"></a></p>
<p>I've spent less than a morning on this project and am very satisfied with the result so far. I will certainly be making
some improvements and printing some more stencils. I'd also like to create a web interface to the program to make it easier
for others to use. You'd just have to upload an image, specify dimensions for the stencil, and then you'd get an STL file generated and
ready to go.</p>
<p>Here are a few more Bitcoin symbols I sprayed around my garage:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1500"><img src="https://img.incoherency.co.uk/1500/thumb"></a> </p>
<p><a class="img" href="https://img.incoherency.co.uk/1501"><img src="https://img.incoherency.co.uk/1501/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/1503"><img src="https://img.incoherency.co.uk/1503/thumb"></a></p>
<p><a class="img" href="https://img.incoherency.co.uk/1504"><img src="https://img.incoherency.co.uk/1504/thumb"></a>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/3d-printed-stencils.html</link>
   <guid>http://incoherency.co.uk/blog/stories/3d-printed-stencils.html</guid>
   <pubDate>Mon, 03 Jul 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Someone cloned my website and is using it to scam people</title>
   <description><![CDATA[I was looking on the DuckDuckGo search results for "anonymous bitcoin sms" today, just to see what was out there.
My SMS Privacy was the top result, as expected. But the second result
was new to me:]]></description>
   <content:encoded><![CDATA[<p>I was looking on the DuckDuckGo search results for "anonymous bitcoin sms" today, just to see what was out there.
My <a href="https://smsprivacy.org/">SMS Privacy</a> was the top result, as expected. But the second result
was new to me:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1483"><img src="https://img.incoherency.co.uk/1483/thumb"></a></p>
<p><b>Update:</b> Kevin has <a href="https://news.ycombinator.com/item?id=14571300">replied on HN</a> and my payment
is now showing up. The site <b>is not a scam</b>, although it has copied an awful lot of text from my site, and payment processing
is seemingly performed at the speed of email. I've left the rest of the article unchanged, but note the site
<b>does</b> appear to basically work.</p>
<p>(I won't hyperlink it here as I don't want to give it any link juice, but you can see the URL in the screenshot.)</p>
<p>I clicked around the site a little and was surprised to find that it had blatantly ripped off almost all of the text from
SMS Privacy, including (with the order slightly rearranged) the example use cases on the home page, the FAQ text, and the getting started guide.</p>
<p>So far, most of this is flattering. It's a bit annoying that it's copying my site without giving any credit, but I
can live with that. The pricing even happens to be just slightly lower than the SMS Privacy pricing. Fair enough, I can
take some competition.</p>
<p>I signed up for an account to see how the user experience was, and things got worse. Suddenly the entire page layout was
almost identical to SMS Privacy, including much of the HTML (although parts of the CSS were missing so it didn't quite
render properly). The greeting on first sign in was identical to SMS Privacy. I tried to see what phone numbers were available to purchase
but couldn't find a way to do so without sending any money. No matter, I can afford to send a few quid to check out a competitor.</p>
<p>The payments page was again very similar to SMS Privacy, with much of the text copied verbatim. I sent some payment and things got even worse.
My payment transaction was first mined over 3 hours ago, and has since had over 20 confirmations, and yet there's still no mention
of it (not even showing up as unconfirmed) on anonymousbtcsms.</p>
<p>So at this point I started thinking it's not just ripping off my text, it's actually a deliberate scam!</p>
<p>There's no evidence that this site can actually provide the service promised. There's not even any evidence that it
can process payments. It just copies the marketing text off my site, then shows a new bitcoin address for each user (I wonder if it's
a hardcoded list?), and the trail ends there. It doesn't handle incoming payments, and
it almost certainly doesn't have any phone numbers for sale.</p>
<p>Shortly after I sent my payment, I sent an email to the contact address listed on the site (k@anonymousbtcsms.com) asking for the copied text to be removed, although I
haven't received a reply and no longer expect to. With the help of some friends, I've since done some investigating.
The whois record for anonymousbtcsms.com names a Kevin Coleman as the domain registrant:</p>
<p><a href="https://img.incoherency.co.uk/1490/"><img src="https://img.incoherency.co.uk/1490/"></a></p>
<p>We found a Kevin
Coleman in Buenos Aires who is a software developer at Spark Start. His site (www.kcoleman.me) includes a link to anonymousbtcsms so it seems as though he is
the real developer of the project and is not trying to hide it. From browsing the site, a couple of his "Coleman Laws" are particularly notable:</p>
<p><blockquote>8. There is nothing more critical to true success than openness, honesty and integrity.</blockquote>
<blockquote>18. Don’t ever take credit for others' work.</blockquote></p>
<p>I have emailed Kevin's personal email address but he hadn't replied by the time I published this post.</p>
<p>My suspicion is that this is all an accident, and that Kevin is basically a decent person: I imagine at one point he was intending to compete with SMS Privacy. On the basis of
"fake it until you make it", he got an MVP up and running quickly by copying the SMS Privacy marketing text and accepting payments straight away,
but he lost interest and never got around to actually building the service.</p>
<p>If you're a would-be customer: stay away from anonymousbtcsms. It doesn't provide the service it promises.</p>
<p>If you're Kevin: please, stop ripping people off. Either finish the project or take the site down. The current situation is completely indistinguishable
from a scam.</p>
<p>Thanks for reading.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/anonymousbtcsms-scam.html</link>
   <guid>http://incoherency.co.uk/blog/stories/anonymousbtcsms-scam.html</guid>
   <pubDate>Fri, 16 Jun 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Hardbin: The World's Most Secure Encrypted Pastebin</title>
   <description><![CDATA[Over the past week I've been working on hardbin.
Hardbin is an encrypted pastebin, with the decryption key passed in the URL fragment,
and the code and data served securely with IPFS. (IPFS is a distributed content-addressable
storage system that is web-compatible; it's basically bittorrent for the web).]]></description>
   <content:encoded><![CDATA[<p>Over the past week I've been working on <a href="https://hardbin.com/">hardbin</a>.
Hardbin is an encrypted pastebin, with the decryption key passed in the URL fragment,
and the code and data served securely with IPFS. (IPFS is a distributed content-addressable
storage system that is web-compatible; it's basically bittorrent for the web).</p>
<p><b>You can play with hardbin <a href="https://hardbin.com/">on the hardbin.com public IPFS gateway here</a>.</b></p>
<p>The current IPFS path is <b>/ipfs/QmUGFZAWzWEaHjC1dHAUQ8aKCuKupKsX9vLzhGZV9PLknu/</b> (liable to become out of date:
check on the <a href="https://github.com/jes/hardbin">github repo</a> or <a href="https://hardbin.com/">hardbin.com</a> if
reading this in the future).</p>
<p>If you like, you can view a paste via the ipfs.io public gateway at <a href="https://ipfs.io/ipfs/QmWaHbpkokQvEN7ScqGDZFLDepY3ZsoCk3omg7fvHXinRq/#EkyreKl72W0hStVIQ07qsKb6nVNH23GP">https://ipfs.io/ipfs/QmWaHbpkokQvEN7ScqGDZFLDepY3ZsoCk3omg7fvHXinRq/#EkyreKl72W0hStVIQ07qsKb6nVNH23GP</a>.</p>
<p>You can read a bit more in
<a href="https://github.com/jes/hardbin/blob/master/README.md">README.md on the github repo.</a>.</p>
<p><h2>Background and overview</h2></p>
<p><h3>IPFS</h3></p>
<p>IPFS is a protocol that, given a content hash, can retrieve the corresponding content from any node on the network,
and verify that it got the correct content (because the hash is correct).
Nodes can "pin" content to make sure it stays around, and nodes cache any content that they retrieve. In this manner
it is analogous to bittorrent.</p>
<p>Unlike traditional web URLs, IPFS content is retrieved by specifying the content hash, rather than the location
at which the content can be found. This has some interesting trade-offs: you can't change content after-the-fact,
but nobody else can change content after-the-fact either, content can still be reachable even
if the original hoster goes offline, and high-traffic content doesn't need a CDN as the entire network acts
as a CDN.</p>
<p><h3>Hardbin</h3></p>
<p>Hardbin is a single-page web app implementing an encrypted pastebin. There is no server component, it
relies entirely on IPFS for content delivery and storage. The hardbin code and data are both stored in
IPFS.</p>
<p>To publish a new paste, hardbin publishes a new copy of itself, bundled with the encrypted paste data.
The decryption key is passed in the URL fragment so that it never hits the network.</p>
<p><h3>IPFS gateways</h3></p>
<p>An IPFS gateway is a web server that provides an interface to the IPFS network for web browsers (and other HTTP(S)
clients) to use.</p>
<p>A writable IPFS gateway also provides a mechanism to publish new content to the network.</p>
<p>No IPFS gateway has any more authority than any other, but you need to make sure not to use a gateway
you don't trust as the gateway is able to modify the content it is returning.</p>
<p>A local gateway means you're not trusting a remote server to correctly return IPFS content. It is super
easy to run a local gateway. Start with the IPFS <a href="https://ipfs.io/docs/getting-started/">Getting
Started</a> guide.</p>
<p>Browser extensions like <a href="https://addons.mozilla.org/firefox/addon/ipfs-gateway-redirect/">IPFS
Gateway Redirect</a> for Firefox and <a href="https://chrome.google.com/webstore/detail/ipfs-station/kckhgoigikkadogfdiojcblegfhdnjei">IPFS
Station</a> for Chrome can automatically redirect IPFS paths to a local gateway.</p>
<p><h3>hardbin.com</h3></p>
<p>Hardbin.com is a public writable IPFS gateway. I am operating it to make the hardbin user experience
smoother, but there is no reason it can't be used as a generic IPFS gateway for any application.</p>
<p>I'm not sure how robust it is so it might keel over if people actually start using it. You should all be
using a local gateway anyway though :).</p>
<p>The root URL on hardbin.com redirects to the current latest IPFS hash for the hardbin application.</p>
<p>Most public IPFS gateways are not writable, although there is little reason for this to be the case and I
expect it to change in the future.</p>
<p><h2>Advantages of hardbin</h2></p>
<p><h3>Cryptographic verification</h3></p>
<p>By leveraging IPFS, hardbin gets cryptographic verification of code and data for free. As long as a correct hash is used,
and the gateway is not compromised, the code and data are delivered correctly.</p>
<p><h3>No server-side code required</h3></p>
<p>Hardbin uses the <a href="https://discuss.ipfs.io/t/writeable-http-gateways/210">writable gateway</a> API to store content.</p>
<p>All of the rest of the code runs client-side.</p>
<p>This also means there is no maintenance burden associated with running the server (unless you opt to operate your own
public gateway). And it means even if the original server operator disappears, the users can continue using the software
uninterrupted.</p>
<p><h3>Custom modifications are first-class citizens</h3></p>
<p>There is nothing stopping you from making improvements to hardbin, pinning your version on an IPFS node (or with
<a href="https://ipfsstore.it/">IPFSstore</a>), and then sharing pastes using your custom version of hardbin. You
can even use the hardbin.com public gateway.</p>
<p><h3>Graceful degradation</h3></p>
<p>When used on a local gateway, hardbin has very strong security properties.
Even though the code could be served from anywhere in the world, you can trust
it just as much as if you were running it locally.</p>
<p>When used on a non-local gateway, hardbin still works perfectly fine, but the trust model degrades to
be the same as that of a traditional encrypted pastebin (you have to trust the server operator).</p>
<p>When viewing pastes on a non-writable gateway, hardbin works perfectly fine. When you try to create a new paste,
hardbin checks whether the gateway is writable, and pops up a message with instructions if it is not writable.</p>
<p><h2>Disadvantages of hardbin</h2></p>
<p><h3>Long URLs</h3></p>
<p>Due to the nature of IPFS paths, the URLs are <b>long</b>. There's no getting around this. They're made even longer by
incorporating a decryption key at the end. The key is 32 characters long and provides approximately 190 bits
of keyspace. This could probably be reduced with little ill effect, but the length of the IPFS hash dominates
anyway so the improvement would be minimal.</p>
<p><h3>Custom modifications are first-class citizens</h3></p>
<p>The flip-side of being able to publish arbitrary modifications is that there is nothing visible to distinguish malicious
versions of the code from legitimate ones.</p>
<p>To mitigate this sort of attack, make sure you are using a known-good IPFS hash (the path in the URL). Ideally, write down the hash the
first time you use it, audit the code to make sure you're happy with it, and only use that hash. Certainly do not trust
arbitrary hashes you receive from people you don't trust.</p>
<p><h2>Learn more</h2></p>
<p>Other than reading the <a href="https://github.com/jes/hardbin/blob/master/README.md">README.md on github</a>,
you can learn more about hardbin by emailing me: <a href="mailto:james@incoherency.co.uk">james@incoherency.co.uk</a>.</p>
<p>You can learn more about IPFS by following the <a href="https://ipfs.io/docs/getting-started/">Getting Started</a> guide,
or by emailing me: <a href="mailto:james@incoherency.co.uk">james@incoherency.co.uk</a>.</p>
<p>Please also get in touch to report any issues or confusion you have. I want this stuff to be as easy to understand as possible,
and I want to find out which parts are hard to understand.</p>
<p>Thanks for reading.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/hardbin.html</link>
   <guid>http://incoherency.co.uk/blog/stories/hardbin.html</guid>
   <pubDate>Fri, 19 May 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made a Base58 encoding/decoding tool</title>
   <description><![CDATA[Base58 encoding allows arbitrary
data to be encoded using only alphanumeric characters. It is analogous to
base64 except base58 does not map neatly
on to bytes (4 base64 characters is 3 bytes), and base58 does not include any
non-alphanumeric characters.]]></description>
   <content:encoded><![CDATA[<p><a href="https://en.wikipedia.org/wiki/Base58">Base58</a> encoding allows arbitrary
data to be encoded using only alphanumeric characters. It is analogous to
<a href="https://en.wikipedia.org/wiki/Base64">base64</a> except base58 does not map neatly
on to bytes (4 base64 characters is 3 bytes), and base58 does not include any
non-alphanumeric characters.</p>
<p>Bitcoin addresses are base58-encoded (like "1LEZsggujCJCqsbjRGLr8z3Af4by4gVrXd"), and
so are <a href="https://ipfs.io/">IPFS</a> content hashes (like "QmRWoZ6eCxNhNzSP72UBn9Hu4hYdxXR65Tygd9ysn6eGR2").</p>
<p>Bitcoin and IPFS both use the same base58 alphabet. Ripple and Flickr also use base58 but have incompatible
alphabets. I have only implemented the Bitcoin/IPFS version.</p>
<p><b>You can use my base58 tool at <a href="http://incoherency.co.uk/base58/">http://incoherency.co.uk/base58/</a>
or <a href="https://ipfs.io/ipfs/QmRWoZ6eCxNhNzSP72UBn9Hu4hYdxXR65Tygd9ysn6eGR2/">/ipfs/QmRWoZ6eCxNhNzSP72UBn9Hu4hYdxXR65Tygd9ysn6eGR2/</a>.</b>
There is also a <a href="https://github.com/jes/base58/">github repo</a>.</p>
<p>I made this because <a href="https://falkus.co/">Martin</a> suggested that IPFS hashes could be made more legible
if they were represented with words instead of arbitrary characters. I wanted to represent
the hashes using <a href="https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki">BIP39</a> mnemonics to see what they look like, but I couldn't find any online
tool to perform base58 encoding.</p>
<p>It turns out not to be useful to represent IPFS hashes with BIP39 mnemonics because they are <i>far</i> too unwieldy. Here is
the BIP39 mnemonic for QmRWoZ6eCxNhNzSP72UBn9Hu4hYdxXR65Tygd9ysn6eGR2:</p>
<p><pre><code>connect group poet short ranch you dash first strong view trumpet embrace crowd dose task brown angry napkin mention shift loyal drill eagle rich</code></pre></p>
<p>If you want to learn more about IPFS, I recommend following the <a href="https://ipfs.io/docs/getting-started/">Getting Started</a>
guide. Learning about IPFS is a fascinating rabbithole to go down. I've been evangelising IPFS this week to anybody who'll listen. I promise
you won't regret it.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/base58.html</link>
   <guid>http://incoherency.co.uk/blog/stories/base58.html</guid>
   <pubDate>Sat, 13 May 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to use bitaddress.org securely (spoiler: use IPFS)</title>
   <description><![CDATA[Bitaddress.org is a single-page web app for generating Bitcoin paper wallets.
It's a great tool, and runs entirely client-side so (in theory) you can audit the code and don't have to trust that
the server is not stealing your keys.]]></description>
   <content:encoded><![CDATA[<p><a href="https://bitaddress.org/">Bitaddress.org</a> is a single-page web app for generating Bitcoin paper wallets.
It's a great tool, and runs entirely client-side so (in theory) you can audit the code and don't have to trust that
the server is not stealing your keys.</p>
<p><h3>The Problem</h3></p>
<p>Unfortunately, unless you download the code and host it yourself, you have to audit the code <i>every time you use it</i>,
otherwise the server could simply start shipping malicious Javascript at any time. This could be because the author
has moved over to the dark side, because he has been coerced by criminals
or his local powers-that-be, or simply because his server has been compromised.</p>
<p><h3>The Solution</h3></p>
<p>Fortunately, with <a href="https://ipfs.io/">IPFS</a>, we can do better. (IPFS is a distributed content-addressable
storage system that is web-compatible; it's basically bittorrent for the web).</p>
<p>With IPFS, we only need to audit the code once, and then we know that every time we access the same IPFS path, we
are getting exactly the same content, and <i>nobody at all</i> can modify it, short of breaking SHA256. We don't even
need the original hosting location to stay online: as long as anybody in the network still has the content, we can
continue to retrieve it. Since we know the <i>content</i> is correct, we don't need to care about its <i>location</i>.</p>
<p><h3>Bitaddress.org on IPFS</h3></p>
<p><b>The IPFS path for bitaddress.org</b> (from <a href="https://github.com/pointbiz/bitaddress.org/commit/72aefc03e0d150c52780294927d95262b711f602">commit <tt>72aefc0</tt></a>) is
<b><a href="https://ipfs.io/ipfs/QmYz4bkhtdkGRLFtago2hoNucrfUy5bHwrun8N8XJrrKWA">/ipfs/QmYz4bkhtdkGRLFtago2hoNucrfUy5bHwrun8N8XJrrKWA</a></b></p>
<p>The astute will observe that this hyperlink goes to the ipfs.io web gateway, and therefore ipfs.io can be compromised in all of the same
ways bitaddress.org could be compromised: this is true. Canonical IPFS paths look like <tt>/ipfs/QmYz4b...</tt> (no hostname) and are accessed
without using a gateway, but browsers do not yet support IPFS natively.</p>
<p>If you want to use IPFS without trusting a web
gateway, you can already do so today! Follow the <a href="https://ipfs.io/docs/getting-started/">Getting Started guide</a> and then
install a browser extension like <a href="https://addons.mozilla.org/firefox/addon/ipfs-gateway-redirect/">IPFS
Gateway Redirect</a> for Firefox or <a href="https://chrome.google.com/webstore/detail/ipfs-station/kckhgoigikkadogfdiojcblegfhdnjei">IPFS
Station</a> for Chrome, and IPFS gateway URLs (like the above) will be automatically redirected to your local IPFS node. This is
easy to do, but if you
want help setting this up please just email me and I'd be delighted to walk you through it:
<a href="mailto:james@incoherency.co.uk">james@incoherency.co.uk</a>.</p>
<p>The astute will also note that bugfixes or other updates to bitaddress.org will not be made available at that IPFS path: this is also true. This is
a feature as much as it is a bug; it is simply a consequence of the fact that nobody can change the code. If you want to use an updated
version of bitaddress.org, you need to publish that version on IPFS and distribute the new IPFS path. But only one person has to do this, and
then everybody benefits. It's akin to shipping updates to any other non-auto-updating client-side software.</p>
<p><h3>What I did</h3></p>
<p>After <a href="https://ipfs.io/docs/install/">Installing IPFS</a> (extremely quick and simple, and no external dependencies), publishing
bitaddress.org on IPFS went as follows:</p>
<p><pre><code>$ git clone https://github.com/pointbiz/bitaddress.org
$ cp bitaddress.org/bitaddress.org.html bitaddress.org/index.html
$ ipfs add -r bitaddress.org/</code></pre></p>
<p>(I copied <tt>bitaddress.org.html</tt> to <tt>index.html</tt> for sake of convenience; it's not strictly necessary but would make
the URLs more cumbersome if we had to append <tt>/bitaddress.org.html</tt> all the time).</p>
<p>The last line of output from <tt>ipfs add</tt> was:</p>
<p><pre><code>added QmYz4bkhtdkGRLFtago2hoNucrfUy5bHwrun8N8XJrrKWA bitaddress.org</code></pre></p>
<p>This tells us the hash of the directory we just added. This is now available, immediately, everywhere with IPFS connectivity (which, thanks
to public gateways like the one at <tt>ipfs.io</tt>, is
<i>everywhere on the web</i>), at <tt>/ipfs/QmYz4bkhtdkGRLFtago2hoNucrfUy5bHwrun8N8XJrrKWA</tt>.</p>
<p>I also have a couple more IPFS nodes, so to maximise the availability (e.g. to avoid the situation where my laptop is the only node
with the content, and is not online), I have <a href="https://ipfs.io/docs/commands/#ipfs-pin-add">pinned</a>
the hash on those nodes:</p>
<p><pre><code>$ ipfs pin add QmYz4bkhtdkGRLFtago2hoNucrfUy5bHwrun8N8XJrrKWA</code></pre></p>
<p>If you want to make sure it stays online even if I disappear, you can pin it too.</p>
<p><h3>How you can verify that I did it correctly</h3></p>
<p>The above is all well and good, but you really need to make sure that I published the <i>real</i> bitaddress.org content, and
didn't insert any of my own modifications (or, at least, <i>somebody</i> needs to do it, and everybody else can trust him, or
verify it themselves if they're not sure). You have 2 approaches:</p>
<p><h4>1.) Duplicate what I did</h4></p>
<p>Clone the git repo, checkout commit <tt>72aefc0</tt>, copy <tt>bitaddress.org.html</tt> to <tt>index.html</tt>, and then add the
whole directory (excluding <tt>.git/</tt>, but the default behaviour is to ignore hidden files anyway).
If I didn't cheat, you should get the same hash at the end: <tt>QmYz4bkhtdkGRLFtago2hoNucrfUy5bHwrun8N8XJrrKWA</tt></p>
<p><h4>2.) Check that the content in IPFS matches the content in git</h4></p>
<p>Alternatively, you can clone the git repo, checkout commit <tt>72aefc0</tt>, and then download the content from IPFS:</p>
<p><pre><code>$ ipfs get QmYz4bkhtdkGRLFtago2hoNucrfUy5bHwrun8N8XJrrKWA</code></pre></p>
<p>The content will be downloaded to a directory called <tt>QmYz4bkhtdkGRLFtago2hoNucrfUy5bHwrun8N8XJrrKWA</tt>. You can then use <tt>diff</tt>, <tt>sha256sum</tt>,
or any other tools you enjoy using, to look for differences between the git repo directory and the IPFS content directory.</p>
<p><h3>Other Bitcoin-related tools</h3></p>
<p>While I was at it, I also decided to publish <a href="http://incoherency.co.uk/stegoseed/">stegoseed</a> and <a href="https://iancoleman.github.io/bip39/">Ian Coleman's BIP39 tool</a> on IPFS.</p>
<p><h4>bitaddress.org</h4></p>
<p>IPFS path: <a href="https://ipfs.io/ipfs/QmYz4bkhtdkGRLFtago2hoNucrfUy5bHwrun8N8XJrrKWA">/ipfs/QmYz4bkhtdkGRLFtago2hoNucrfUy5bHwrun8N8XJrrKWA</a><br>
Web URL: <a href="https://bitaddress.org/">https://bitaddress.org</a><br>
Git repo: <a href="https://github.com/pointbiz/bitaddress.org">https://github.com/pointbiz/bitaddress.org</a><br>
Git commit: <a href="https://github.com/pointbiz/bitaddress.org/commit/72aefc03e0d150c52780294927d95262b711f602"><tt>72aefc0</tt></a><br></p>
<p>I copied <tt>bitaddress.org.html</tt> to <tt>index.html</tt> before adding the directory to IPFS.</p>
<p><h4>stegoseed</h4></p>
<p>IPFS path: <a href="https://ipfs.io/ipfs/QmSaJUuCesYDpxLbHrrKA3m2HjN4YcufhAtDH2achrY97z">/ipfs/QmSaJUuCesYDpxLbHrrKA3m2HjN4YcufhAtDH2achrY97z</a><br>
Web URL: <a href="http://incoherency.co.uk/stegoseed/">http://incoherency.co.uk/stegoseed/</a><br>
Git repo: <a href="https://github.com/jes/stegoseed">https://github.com/jes/stegoseed</a><br>
Git commit: <a href="https://github.com/jes/stegoseed/commit/24886cd683d3af7f4312568fb310d2cb09b2cc23"><tt>24886cd</tt></a><br></p>
<p>Didn't change any files as index.html already exists.</p>
<p><h4>Ian Coleman's BIP39 tool</h4></p>
<p>IPFS path: <a href="https://ipfs.io/ipfs/QmaF4DKh6nyYfrboYRvzbJarY9ntRUup2xPqs2DpbaoWnh">/ipfs/QmaF4DKh6nyYfrboYRvzbJarY9ntRUup2xPqs2DpbaoWnh</a><br>
Web URL: <a href="https://iancoleman.github.io/bip39/">https://iancoleman.github.io/bip39/</a><br>
Git repo: <a href="https://github.com/iancoleman/bip39">https://github.com/iancoleman/bip39</a><br>
Git commit: <a href="https://github.com/iancoleman/bip39/commit/0d1150545f04843a1fbe09f2e8f612a800aed7a8"><tt>0d11505</tt></a><br></p>
<p>I copied <tt>bip39-standalone.html</tt> to <tt>index.html</tt> before adding the directory to IPFS.</p>
<p><h3>Host your client-side applications on IPFS</h3></p>
<p>If you have written any client-side applications, you can host them on IPFS in a matter of minutes and reap all of the benefits:</p>
<p><ul>
<li>1.) Nobody has to trust you</li>
<li>2.) Nobody stands to gain anything from compromising you</li>
<li>3.) You don't need your server to handle spikes in load - a spike in users accessing the content means
a corresponding spike in the amount of nodes able to serve the content</li>
<li>4.) You don't need to run a persistent server at all (but your content might disappear if you can't guarantee there is always at least one node hosting it - won't
be a problem for popular content)</li>
</ul></p>
<p>It's quick and easy. In fact, it's <i>significantly</i> easier to host content on IPFS than on a traditional website, and also comes
with almost zero maintenance burden as you don't need to run a server. Just run <tt>ipfs add</tt>, and your content is online for all to see. If you don't
already have some traditional hosting setup, you could consider going IPFS-only.</p>
<p><h3>Where to learn more about IPFS</h3></p>
<p>(Disclaimer: I'm absolutely nothing to do with the IPFS project, just a massive fanboy).</p>
<p>If you haven't done so already, follow the IPFS <a href="https://ipfs.io/docs/getting-started/">Getting Started</a> guide, and then install
a gateway-redirecting browser extension. The other <a href="https://ipfs.io/docs/">IPFS documentation</a> is also top quality.</p>
<p>The IRC channel #ipfs on Freenode is quite lively, lots of discussion happens on the <a href="https://github.com/ipfs/">ipfs github project</a>,
and there is a discussion board at <a href="https://discuss.ipfs.io/">discuss.ipfs.io</a>.</p>
<p>Please email me if you have anything to say. I want to hear from you: <a href="mailto:james@incoherency.co.uk">james@incoherency.co.uk</a>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/bitaddress-on-ipfs.html</link>
   <guid>http://incoherency.co.uk/blog/stories/bitaddress-on-ipfs.html</guid>
   <pubDate>Wed, 10 May 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I've been playing with IPFS</title>
   <description><![CDATA[There was an article on Hacker News yesterday about Uncensorable Wikipedia on IPFS.
I read it with great interest (I recommend you read it too) and ended up going down a huge rabbit hole of learning about IPFS.]]></description>
   <content:encoded><![CDATA[<p>There was an article on Hacker News yesterday about <a href="https://ipfs.io/blog/24-uncensorable-wikipedia/">Uncensorable Wikipedia on IPFS</a>.
I read it with great interest (I recommend you read it too) and ended up going down a huge rabbit hole of learning about IPFS.</p>
<p>IPFS is the "Inter-Planetary File System". I recommend watching <a href="https://www.youtube.com/watch?v=jONZtXMu03w">this YouTube video</a> if
you want to kill an hour listening to a fascinating talk.</p>
<p>IPFS is a distributed content-addressable storage system (imagine git combined with bittorrent), where any piece of data only sticks
around as long as there are nodes on the network that find it interesting. Content is looked up by its hash, which means you don't
care who serves you the content, you can always verify that you received the correct version, and you also don't care if the
original hoster of the content disappears. A "copy" of the same content from somebody else on the IPFS network is just
as authoritative as the "original". In fact, unless you go out of your way to find out, you won't even <i>know</i> which node on the network
you received the content from. It all just works. And this network is live and available <i>right now</i>. It is truly mind-blowing.</p>
<p>Anyway, the upshot of my dive down this rabbit hole, so far, is that my blog is now available on IPFS, using IPNS (the "Inter-Planetary Name System";
basically a way to update content without having to distribute a new hash) at
<a href="https://ipfs.io/ipns/QmdnD2bUSWcZorAwcTs7rftNm19YZXLWkmdefsvrjdMmAe/">/ipns/QmdnD2bUSWcZorAwcTs7rftNm19YZXLWkmdefsvrjdMmAe/</a>.
That hyperlink goes to <tt>https://ipfs.io/ipns/QmdnD2bUSWcZorAwcTs7rftNm19YZXLWkmdefsvrjdMmAe/</tt>, which is a public web-to-IPFS gateway.
If you would rather use a different gateway, simply replace <tt>https://ipfs.io</tt> with the address of your gateway (e.g. <tt>http://localhost:8080</tt> if
you're running <tt>go-ipfs</tt> locally).</p>
<p>I am currently running a public gateway at <tt>https://ipfs.jes.xxx</tt>, so the following link works just as well, as long as my gateway is running:
<a href="https://ipfs.jes.xxx/ipns/QmdnD2bUSWcZorAwcTs7rftNm19YZXLWkmdefsvrjdMmAe/">https://ipfs.jes.xxx/ipns/QmdnD2bUSWcZorAwcTs7rftNm19YZXLWkmdefsvrjdMmAe/</a></p>
<p>The IPFS tooling is impressively mature and easy to use, and I recommend playing with it.
Gio d'Amelio's article on <a href="https://ipfs.io/ipfs/QmdPtC3T7Kcu9iJg6hYzLBWR5XCDcYMY7HV685E3kH3EcS/2015/09/15/hosting-a-website-on-ipfs/">hosting
a website on IPFS</a> is helpful, and the <a href="https://ipfs.io/docs/getting-started/">Getting Started guide</a> is super easy to follow.</p>
<p>So go forth! And play with IPFS.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/ipfs.html</link>
   <guid>http://incoherency.co.uk/blog/stories/ipfs.html</guid>
   <pubDate>Tue, 09 May 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I semi-deanonymised some MetaMask users, and they were absolutely loaded</title>
   <description><![CDATA[Yesterday, I published a post about drive-by identification of
MetaMask users (and submitted it to /r/ethereum on reddit). The post included an implementation (now disabled) of
an attack that could associate website visitors' IP addresses with their Ethereum accounts, with
no user interaction required. This is what I found.]]></description>
   <content:encoded><![CDATA[<p>Yesterday, I published a post about <a href="https://incoherency.co.uk/blog/stories/metamask-identification.html">drive-by identification of
MetaMask users</a> (and submitted it to /r/ethereum on reddit). The post included an implementation (now disabled) of
an attack that could associate website visitors' IP addresses with their Ethereum accounts, with
no user interaction required. This is what I found.</p>
<p><h3>The logs</h3></p>
<p>Of around 400 unique IP addresses that accessed the blog post, around 100 submitted Ethereum account addresses
to the logging endpoint. That's a higher ratio than expected, although it's likely that the title of the post selected
for clicks from MetaMask users.</p>
<p>Of the ~100 MetaMask users, around 2 in 3 were on mainnet. Most of the rest were using Ropsten testnet,
but a few were using (distinct) network ids that correspond to very recent Unix timestamps in milliseconds. Most likely
private testnets.</p>
<p>Of the mainnet users, I received ~100 unique Ethereum addresses (<tt>web3.eth.getAccounts()</tt> can return more than
one account per user, although most users only had one). Approximately 1 in 3 addresses were completely unused, but the
remainder had a combined balance of <b>over 6,000 ETH</b> (about <b>$500,000</b>). Yes, really. From less than 100 users.</p>
<p><h3>MetaMask</h3></p>
<p>Dan Finlay (a MetaMask developer) wrote <a href="https://www.reddit.com/r/ethereum/comments/68mv7k/driveby_identification_of_metamask_users/dgzoccg/">a handful of reddit comments</a>
on the topic. He pointed out that MetaMask considers itself a developer beta (although the MetaMask homepage doesn't mention this). He
also pointed out that MetaMask already had <a href="https://github.com/MetaMask/metamask-plugin/issues/714">a GitHub issue</a> open for this,
which implies they intend to fix it eventually.</p>
<p>Given that MetaMask is a developer beta, there is an <i>awful</i> lot of money being entrusted to it.</p>
<p><h3>Irresponsible Disclosure</h3></p>
<p>Nick Johnson (an Ethereum developer) <a href="https://www.reddit.com/r/ethereum/comments/68mv7k/driveby_identification_of_metamask_users/dgzolmv/">called me
out</a> for irresponsibly disclosing the vulnerability. A handful of people defended the full disclosure. I don't think it was a problem.</p>
<p>And besides, if I had disclosed it "responsibly", I wouldn't have been able to use it myself, and where's the fun in that?</p>
<p><h3>Cleanup</h3></p>
<p>Obviously, as much fun as it was to run a live proof of concept, I can't just leave a semi-exploit "in the wild" indefinitely.
The original blog post still shows what it finds about users' accounts, but no longer ships the information off to my server.</p>
<p>Furthermore, having access to this semi-identifying information is nothing but a liability,
so I have retroactively removed all record of the information, apart from the aggregated analysis in this post.</p>
<p>So it doesn't matter how much money/violence you have to offer, I can't give you the information. You'll just have to
run the attack yourself.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/metamask-identification-results.html</link>
   <guid>http://incoherency.co.uk/blog/stories/metamask-identification-results.html</guid>
   <pubDate>Tue, 02 May 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Drive-by identification of MetaMask users</title>
   <description><![CDATA[
MetaMask is a Chrome plugin that turns an ordinary
Chrome browser into a Dapp browser.
A Dapp is a web app that is augmented to use
the browser's local web3
object to access the Ethereum blockchain.
Compared to Mist, another Dapp browser,
MetaMask streamlines the user interface by not
requiring users to "Connect" an account before using it in a Dapp.]]></description>
   <content:encoded><![CDATA[<p>
<a href="https://metamask.io/">MetaMask</a> is a Chrome plugin that turns an ordinary
Chrome browser into a Dapp browser.
A Dapp is a web app that is augmented to use
the browser's local <a href="https://github.com/ethereum/wiki/wiki/JavaScript-API">web3</a>
object to access the Ethereum blockchain.
Compared to <a href="https://github.com/ethereum/mist/releases">Mist</a>, another Dapp browser,
MetaMask streamlines the user interface by not
requiring users to "Connect" an account before using it in a Dapp.</p>
<p>Unfortunately, <i>every</i> website is just a Dapp that doesn't know it yet.
And in MetaMask, you don't need to get any user permission before retrieving his account
information using web3.</p>
<p>If a website you ended up on were to use MetaMask to collect a list of your Ethereum
accounts and ship them off to a remote location to be permanently associated with your current IP address
and User-Agent string, you would be none the wiser. There is
no user permission required, and there is no feedback in the user interface. It
is completely silent.
Even if you
inspected the source code and noticed the behaviour, by the time you realised it would
be too late.</p>
<p>This blog post shows this. <span id="metamask-info">But it looks like you're either not
using MetaMask, or are otherwise not vulnerable. Try viewing this post in Chrome with MetaMask
installed.</span></p>
<p><script type="text/javascript">
    setTimeout(function() {
        if(typeof web3 != 'undefined') {
            web3.version.getNetwork(function(err,res) {
                if (err) return;
                var networkid = res;
                var net = {1: "mainnet", 3: "Ropsten testnet", 42: "Kovan testnet"};
                var networkname = net[networkid] || "Network #" + networkid;
                web3.eth.getAccounts(function(err,res) {
                    if (err) return;
                    if (res.length == 0) return;
                    var s;
                    var log = res.join(',');
                    if (res.length == 1) {
                        s = "You're using Ethereum account <b>" + res[0] + "</b>";
                    } else {
                        s = "You're using multiple Ethereum accounts: ";
                        for (var i = 0; i < res.length; i++) {
                            s += "<b>" + res[i] + "</b>";
                            if (i != res.length-1)
                                s += ", ";
                        }
                    }
                    s += " on <b>" + networkname + "</b>.";
                    document.getElementById('metamask-info').innerHTML = s;
                });
            });
        }
    }, 0);
</script></p>
<p>If you're interested in your financial privacy... don't use MetaMask.</p>
<p><b>Update:</b> Dan from MetaMask <a href="https://www.reddit.com/r/ethereum/comments/68mv7k/driveby_identification_of_metamask_users/dgzoccg/">replied on reddit</a>.
It turns out MetaMask already have a <a href="https://github.com/MetaMask/metamask-plugin/issues/714">github issue for this</a>. Presumably
this means it'll get fixed eventually, which is good news.</p>
<p><b>Update 2:</b> For the first 24 hours, this post remotely logged the Ethereum account addresses. <a href="https://incoherency.co.uk/blog/stories/metamask-identification-results.html">Write-up of results available here</a>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/metamask-identification.html</link>
   <guid>http://incoherency.co.uk/blog/stories/metamask-identification.html</guid>
   <pubDate>Mon, 01 May 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>eBay don't understand why people dodge their fees</title>
   <description><![CDATA[I've been selling some stuff on eBay recently, and I had a pretty crap experience with
one particular item.]]></description>
   <content:encoded><![CDATA[<p>I've been selling some stuff on eBay recently, and I had a pretty crap experience with
one particular item.</p>
<p>I created an auction to sell the item. A handful of people contacted me asking to end the
auction early, but I refused as I am aware that eBay frown upon this, and it screws them
out of receiving their fee. So I let it run until the end, and it sold for &pound;132, and
eBay took their 10% final value fee from my PayPal account.</p>
<p>Unfortunately, the winning bidder did not pay. I created a "second chance offer" to sell
it to some of the other bidders, but none of them wanted it either.</p>
<p>At this point, I had to create an "unpaid item dispute" and wait until eBay's Kafka-esque
system would be so
gracious as to give me back the final value fee on the item which I still had not
received any payment for.</p>
<p>After stewing for a week or so, I relisted the item on eBay. Once again, I received offers from people
asking me to end the auction early. This time I accepted one, and a gentleman drove approximately
100 miles to come to my house and hand over &pound;80 in cash for the item. This is clearly a superior way
to sell the item: I actually received the money this way.</p>
<p>I then marked the item as "no longer for sale" on eBay.</p>
<p>eBay sent me a rather threatening email suggesting that I was violating their policies and
that I was generally a bad person for trying to dodge their fees.</p>
<p>But here's the thing: I wasn't trying to dodge their fees. My <i>only</i> interest was in
selling the item for a reasonable price, with a minimum of hassle. I already tried to play
by their rules, and it did not work.</p>
<p>The reason people are ending auctions early and selling outside the auction is not to avoid
the 10% fee. It's to avoid the hassle of non-paying bidders. eBay need to fix that before
they accuse sellers of fraud.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/ebay.html</link>
   <guid>http://incoherency.co.uk/blog/stories/ebay.html</guid>
   <pubDate>Sun, 30 Apr 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Is the Large Bitcoin Collider malware?</title>
   <description><![CDATA[Yesterday, /u/SopaXorzTaker submitted a post to r/Bitcoin
suggesting the Large Bitcoin Collider (a.k.a. "LBC", not to be confused with Local Bitcoins) is probably malicious. He did a great service to the community by doing so.]]></description>
   <content:encoded><![CDATA[<p>Yesterday, <a href="https://www.reddit.com/user/SopaXorzTaker">/u/SopaXorzTaker</a> submitted a post to r/Bitcoin
suggesting the <a href="https://lbc.cryptoguru.org/">Large Bitcoin Collider</a> (a.k.a. "LBC", not to be confused with Local Bitcoins) is <a href="https://www.reddit.com/r/Bitcoin/comments/65uoaq/do_not_run_the_large_bitcoin_collider_client_its/">probably malicious</a>. He did a great service to the community by doing so.</p>
<p>This was the first I'd heard of LBC, although it has apparently received a lot of publicity lately.</p>
<p>I took a look through the source <a href="https://www.reddit.com/r/Bitcoin/comments/65uoaq/do_not_run_the_large_bitcoin_collider_client_its/dgdencb/">and wrote
up my findings</a> (most notably that LBC includes a remote code execution backdoor, but also that it explicitly disables hostname checking of the server's SSL certificate).</p>
<p>Eventually, the creator of LBC, <a href="https://www.reddit.com/user/therico666">/u/therico666</a>, showed up to defend his software.</p>
<p>LBC attempts to brute-force Bitcoin keys by using a distributed "pool" of users running the software, and then distributing any funds
among the pool participants. It is similar in
concept to a mining pool except for 2 massive flaws:</p>
<p>1.) The search space is so overwhelmingly large that it will find nothing but weakly-generated keys.<br>
2.) There is no way to do proof of work: it relies on honest clients.</p>
<p>To solve flaw number 2, LBC attempts to ensure that nobody can run a modified client. Part of this includes <b>making
the client run any arbitrary code the server sends it</b>. This way the server can send some code snippets that MD5 the
script, or do other arbitrary checkings, and if the client doesn't respond with the expected response, it gets blacklisted.</p>
<p>therico666 has remained anonymous. In itself, there is nothing wrong with this. Everybody has a right to remain anonymous online.
But if you're shipping software that includes a remote code execution backdoor, and asking people to trust you, you really need to back that up with some
reputation.</p>
<p>Given therico666's continued anonymity, and flaw number 1, many people believe that LBC was a trojan horse.
That it was not <i>actually</i> trying to brute-force
Bitcoin keys, it was just building up an installed base of users, until there is a large enough user base, and then the
server would remote-deploy code to sweep up wallet files and send them off to the server. LBC would then steal as much money as it
could from the wallet files, and may or may not distribute the funds to pool participants.</p>
<p>The <a href="https://lbc.cryptoguru.org/download">LBC download page</a> now gives lots of warnings about how LBC includes
a remote code execution backdoor, although this was notably not present before yesterday's drama.</p>
<p>Also notable is that (despite claims to the contrary), LBC has <i>still</i> not fixed the trivially-easy-to-fix hostname verification vulnerability.
At best, this is a level of sloppiness that is inexcusable alongside remote code execution.
At worst, this might be a way to claim plausible deniability if LBC is ever shown
to have executed malicious code on a user's computer (It wasn't us! It was just a security mistake!).</p>
<p>Finally, many of the techniques used in LBC are strongly reminiscent of techniques used in malware: Verifying the hash of the file.
Automatically downloading and installing dependencies without asking for permission. Hiding code snippets in arrays of numbers disguised as "test data", which get decoded and executed later.
At a minimum, I would suggest the developers of LBC have prior experience with malware development.</p>
<p>So I won't be running LBC. And neither should you.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/large-bitcoin-collider.html</link>
   <guid>http://incoherency.co.uk/blog/stories/large-bitcoin-collider.html</guid>
   <pubDate>Tue, 18 Apr 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made a Rhyming Dictionary</title>
   <description><![CDATA[Some friends and I were trying to come up with rhymes for "mowing", to help us think of a witty
name for a lawnmower racing team. This seemed like a job for a machine, so I looked online for
something that might help.]]></description>
   <content:encoded><![CDATA[<p>Some friends and I were trying to come up with rhymes for "mowing", to help us think of a witty
name for a lawnmower racing team. This seemed like a job for a machine, so I looked online for
something that might help.</p>
<p><a href="http://rhymezone.com/">RhymeZone</a> seemed to be the best option. It sometimes comes up with some good rhymes, but it also misses some obvious ones,
and gives some really bad ones. And it is slow and the interface is annoying.</p>
<p>It seemed like a fun project to try to implement an alternative rhyming dictionary, so I did.
You can play with it here: <a href="http://rhyme.jes.xxx/">Rhyming
Dictionary</a>.</p>
<p>I started with the Simplest Thing That Could Possibly Work: I ran <a href="https://en.wikipedia.org/wiki/Soundex">Soundex</a> on the input
word and the dictionary words, and output the dictionary words that have similar Soundex output.</p>
<p>Since
Soundex is mostly concerned with the starts of words, this didn't work very well <i>at all</i>.
I tried various ways to fix this,
and <a href="https://en.wikipedia.org/wiki/Metaphone">various</a> <a href="https://en.wikipedia.org/wiki/Metaphone#Double_Metaphone">other</a> sounds-like algorithms, and ended up going down quite a rabbit hole.
It all boiled down to "find words with suffixes that are spelled the same", which clearly
is not adequate (e.g. "pause" rhymes with "paws" but doesn't even share a 1-character suffix).</p>
<p>My next thought was to use a text-to-speech engine to convert the input words to phoneme strings, and then compare
suffixes of the phoneme strings. This worked much better.</p>
<p><a href="http://espeak.sourceforge.net/">eSpeak</a> can output the phonemes it's generating (<tt>-x</tt>),
and can suppress sound generation (<tt>-q</tt>). <tt>espeak -qx</tt> does exactly what we want: it takes
words as input and gives phonemes as output, without actually speaking them. Perfect.</p>
<p>Example:</p>
<p><pre><code>$ espeax -qx
hello world
 h@l'oU w'3:ld
pause
 p'O:z
paws
 p'O:z</code></pre></p>
<p>I preprocessed all of the words in my dictionary (101K words) to find their eSpeak phoneme strings, and wrote a function to find rhymes. It simply takes the eSpeak phoneme string for the input word and proceeds as follows:</p>
<p>1.) Output all dictionary words (if any) that have this phoneme string as a suffix.<br>
2.) Remove the first character from the phoneme string.<br>
3.) Loop back to (1.) if any characters remain in the phoneme string.</p>
<p>This means those dictionary words that share longer suffxes of phonemes (i.e. the best rhymes) are output first.</p>
<p>I then wrote a small <a href="http://mojolicious.org/">Mojolicious</a> app to expose the rhyme-finding function over HTTP, and a
user interface.</p>
<p>The end result is pretty good. It comes up with better rhymes than RhymeZone, more quickly,
and with a less annoying interface. Great success.</p>
<p>Here's the link again: <a href="http://rhyme.jes.xxx/">Rhyming Dictionary</a>.</p>
<p>And the lawnmower racing team? Mowing Nowhere Fast.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/rhyming-dictionary.html</link>
   <guid>http://incoherency.co.uk/blog/stories/rhyming-dictionary.html</guid>
   <pubDate>Mon, 17 Apr 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I started accepting 0-conf Bitcoin payments, and it was great</title>
   <description><![CDATA[Customers of SMS Privacy have been frustrated with long
confirmation times for Bitcoin payments. Even though I only required 1 confirmation, it can still
take a long time for that first confirmation if the transaction was accidentally sent with a fee that
is too low. Instead of sending money and being able to use the service immediately, customers sometimes had
to wait hours. This is immensely frustrating for a legitimate customer: you've sent the money, you're
not trying to steal anything, why do you have to wait?]]></description>
   <content:encoded><![CDATA[<p>Customers of <a href="https://smsprivacy.org/">SMS Privacy</a> have been frustrated with long
confirmation times for Bitcoin payments. Even though I only required 1 confirmation, it can still
take a long time for that first confirmation if the transaction was accidentally sent with a fee that
is too low. Instead of sending money and being able to use the service immediately, customers sometimes had
to wait hours. This is immensely frustrating for a legitimate customer: you've sent the money, you're
not trying to steal anything, why do you have to wait?</p>
<p>In time, this issue will be solved by improved fee calculation in wallet software, and by second-layer
payment methods. In the meantime, I decided
to experiment with accepting unconfirmed payments to improve the user experience. (For those less familiar
with Bitcoin: unconfirmed payments can be "double-spent" meaning that although a transaction paying you exists on the
network, it can be replaced by a different transaction that
spends the same money to somebody else; once the transaction is included in a block, the cost of double-spending rises significantly).</p>
<p><h3>Methodology</h3></p>
<p>For my experiment, instead of waiting for 1 confirmation before crediting payments to user balances, I
made my software credit the user's balance as soon as it sees the transaction, for payments up to 0.02 BTC.</p>
<p>I was expecting a certain level of fraud (i.e. some people would double-spend and steal the money, not least
because the service is totally anonymous). But
this is fine as long as the increased profits due to improved user experience outweigh the losses due to fraud.</p>
<p><a href="http://luke.dashjr.org/">Luke Dashjr</a> told me that making it easy to scam me would
<a href="https://www.reddit.com/r/Bitcoin/comments/5t5jeo/best_practices_for_accepting_0conf_transactions/ddkh5a9/">"attract the wrong kind of people"</a>,
and that he suspects SMS Privacy is particularly prone to this. So, to limit the maximum exposure to double-spends, I added a limit of 0.1 BTC credited unconfirmed payments: once
there is 0.1 BTC of credited payments that have 0 confirmations, SMS Privacy would revert to requiring
1 confirmation for all payments.</p>
<p><h3>Results</h3></p>
<p>I started this about a month ago.</p>
<p>There have so far been 0 instances of double-spend attacks against SMS Privacy. 0 losses due to double-spends.
I was very pleased with this, much better than expected. This
integrity, despite complete anonymity, is a credit to the SMS Privacy customers.</p>
<p>Total payments since accepting 0-conf payments have been roughly <b>double</b> what they were in the same time period
prior to accepting 0-conf payments. I don't know if this is 100% attributable to the acceptance of 0-conf payments,
but it is much greater than the organic growth that had been happening up to that point. I also don't have a <i>p</i>-value, sorry.</p>
<p><h3>Conclusion</h3></p>
<p>If the current situation continues (no thefts, and an improved user experience), then I consider the
experiment a great success. I think it caused an increase in purchases, but even if the total amount of payments was completely unaffected by the
change, the improved user experience is a clear win anyway. I intend to leave the new behaviour in effect
for the foreseeable future.</p>
<p>I encourage everybody who accepts Bitcoin payments to try running a similar
experiment. Your customers might surprise you.</p>
<p>Finally, as an aside, I don't know if writing about my findings in this post is necessarily wise: perhaps somebody out there will take it as a provocation and
will now double-spend SMS Privacy as a joke. Hope not :).
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/zeroconf-payments.html</link>
   <guid>http://incoherency.co.uk/blog/stories/zeroconf-payments.html</guid>
   <pubDate>Wed, 29 Mar 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>On the inevitability of the machine-owned enterprise</title>
   <description><![CDATA[A machine-owned enterprise is one in which none of the profits go to any human, and none
of the work is performed by any human. The entirety of the business is owned and operated completely autonomously.]]></description>
   <content:encoded><![CDATA[<p>A machine-owned enterprise is one in which none of the profits go to any human, and none
of the work is performed by any human. The entirety of the business is owned and operated completely autonomously.</p>
<p>The obvious way for such an enterprise to begin is for the owner of a human-owned business to automate away
as much of his work as possible, and then to die without leaving the
business to anybody else. The business would simply continue to take payments, provide services,
and pay bills, until something catastrophic happened that it couldn't respond to automatically.</p>
<p>This is a relatively weak form of machine-owned enterprise, and probably something more deliberate and strong-AI-powered would
be required to ensure long-term survival, but it proves the concept. And plenty of successful human-owned businesses start and end within
a span of 10 years or less. There's no reason a machine-owned business couldn't have an impact on the market, or even be considered "successful", even if it dies in
a much shorter period of time.</p>
<p>That it will become possible for machine-owned enterprises to exist is nothing new (Andreas Antonopoulos uses the hypothetical
example of <a href="https://news.bitcoin.com/self-driving-cars-digital-cash/">a self-driving, self-owning Uber taxi, that
arranges and pays for its own repairs</a>). I argue
that it will not only become <i>possible</i> for machines to wholly own enterprises, but that such enterprises are <i>inevitable</i>.</p>
<p><h3>Automation increases efficiency</h3></p>
<p>When machinery to automate away human labour is first introduced, it results in efficiency gains:
an equivalent product can be made for less cost by using machines in place of humans. Initially this results in increased
profits for the business. Through competition, this results in prices going down. Everyone's a winner, apart
from the workers who are now out of a job. In other words, everyone's a winner, apart from the displaced workers who were used to charging
high prices for services which are now available more cheaply.</p>
<p>Removing the business owner from the equation increases efficiency further still: the business no longer needs to
make any profit whatsoever. In fact there is no real need for a fully-autonomous business to take even a penny more in payments than
it needs to pay in expenses. Traditional businesses, which are paying expenses in addition to enriching the owner (or at least paying
for him to eat), should rightly be out-competed by machine-owned enterprises which don't pay for anybody to eat. Again, everyone's a winner,
apart from the displaced business owners who were used to charging high prices for services which are now available more cheaply.</p>
<p><h3>Efficiency is necessary</h3></p>
<p>Soon after it became possible for machine automation to replace human workers, it became necessary:
any business which did not employ such automation was no longer competitive. Indeed, in the general case, any business
which is too inefficient is out-competed by businesses which are not. Therefore, all else being
equal, machine-owned enterprises will necessarily out-compete human-owned enterprises.</p>
<p>It is likely that human-owned enterprises will have the upper hand for some time, by virtue of being more
flexible in responding to changing market conditions, but I believe it is only a matter of time until this is
no longer true.</p>
<p><h3>Barriers</h3></p>
<p>The first barrier to the existence of a machine-owned enterprise (today, at least) is how it comes into
existence in the first place: no rational business owner would deliberately automate himself out of collecting the profits. The only reason to
start the business in the first place is to collect the profits; there is no motivation to stop doing so.</p>
<p>The next barrier is ensuring its continued survival. The machine must be capable of doing things that aren't part of the core business (which is taking payment,
providing service, paying bills) but are still necessary from time to time: repairing broken equipment, dealing with beauracracy, keeping
up with changing technology demands, and so on.</p>
<p><h3>Properties</h3></p>
<p>There would likely be no customer support available, although community support forums would go some way towards solving this (as they already
do in many cases). And this might not be a big problem: Google already operates most of its services with
almost no customer support (albeit that the user is generally not a "customer" in such cases).</p>
<p>There would probably be no taxes paid. And not just because there are no profits generated, but because there is not even any person to levy the tax on.
A machine-owned enterprise has few good reasons to exist as an entity in the legal system at all, and indeed would have difficulty doing so as it would not have
any humans to name as its directors.</p>
<p>Machine-owned enterprises would be unlikely to succeed in markets that rely on human insight and problem-solving, for obvious reasons.
It's not totally inconceivable that a machine could employ humans to do parts of its work, e.g. by sub-contracting simple
tasks to <a href="https://www.mturk.com/mturk/welcome">Mechanical Turk</a>, but this would likely prove non-viable for tasks that are central to the business.</p>
<p>The most likely place for machine-owned enterprise to spring up is online "software as a service" businesses. It is already possible for software to take payment in
Bitcoin, pay for hosting in Bitcoin, and provide some services without any human in the loop.
As long as market demands do not change too quickly,
and the hosting provider does not switch the machine off, a machine-owned business could operate this way for years without any issue. It is arguably possible
for this to work using more traditional payment methods (e.g. PayPal, Visa), but then a human-related bank account is typically involved, and a human will
periodically be expected to respond to correspondence. The separation of human from business is much more practical with decentralised payment methods, and it
would become even more practical with decentralised hosting methods.</p>
<p><h3>Threats</h3></p>
<p>They will find it hard or impossible to react to changing market conditions that can't be predicted ahead-of-time. Pricing strategy can be
automated to some extent. But if a hot new chat app becomes popular, and customers start expecting hot new chat app integration, the machine will
have a hard time providing it.</p>
<p>They likely won't have any ability to respond appropriately to lawsuits, although it is not inconceivable that they
could automatically hire a lawyer when necessary. And
whether this actually matters is debatable: with no human to threaten with imprisonment, punishment for non-compliance with laws
could prove to be difficult.</p>
<p>A machine-owned enterprise would also have no practical way of responding to slanderous news articles, which might leave customers with an inaccurate perception
of the business. In the arena of social perception, a machine-owned enterprise would be almost completely defenceless.</p>
<p>They would also be defenceless against successful hacking attempts. If somebody hacks into the servers of a traditional online business, the business
owner notices, takes action, and eventually regains control of his business. If a machine-owned business is hacked, the business has no way
to respond and simply becomes the property of whoever hacked into it.</p>
<p><h3>Conclusion</h3></p>
<p>Until very recently, it was not
possible to operate any business without having a person interacting with customers. In many markets, it is now
<i>necessary</i> to do so in order to remain competitive.</p>
<p>It is now possible in some markets to operate almost totally-automated businesses, and to sit back and collect profits while the machine does the
work. To this extent, we are currently living in a "Golden Age" for passive income. Not too long from now it will once again cease to be feasible, as all of the
profit is competed away by autonomous entities which do not need to make any profit.</p>
<p>Machine-ownership of enterprises will likely have less of an effect on society than previous displacements
of workers by automation, simply because there are fewer owners of automatable businesses than there were employees performing automatable tasks. Good
times ahead.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/machine-owned-enterprises.html</link>
   <guid>http://incoherency.co.uk/blog/stories/machine-owned-enterprises.html</guid>
   <pubDate>Wed, 22 Mar 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I don't know how many soldiers are taking drugs, and neither do you</title>
   <description><![CDATA[I read a story, in some online comment section, about a clever trick the US Army used to work out
how many soldiers were taking drugs. It went something like this:]]></description>
   <content:encoded><![CDATA[<p>I read a story, in some online comment section, about a clever trick the US Army used to work out
how many soldiers were taking drugs. It went something like this:</p>
<p><blockquote>
<p>The army asked all the soldiers if they had ever taken any drugs. They had to tick yes or no.</p>
<p>They knew the drug-takers would lie, so they introduced a twist. Each soldier was to toss a coin. If it came up heads, they had to answer the truth. If tails, they had to lie.</p>
<p>Statistically, if no one had been taking drugs, 50% of the final result would be positive for drug use (those who got tails), and 50% would be negative (those who got heads).</p>
<p>But the answer they got was almost 60-40, which meant about 10% of soldiers had been taking drugs. By using this method, they got the soldiers to tell the truth without fear of individual reprisal.</p>
</blockquote></p>
<p>It should be clear that given any individual soldier's answer, it is impossible to determine whether or not
he has been taking drugs. If his answer is "yes", then it means either he got heads and has been taking
drugs, or he got tails and has not been taking drugs. The coin flip is 50:50, so we have no information
about whether or not he has been taking drugs.</p>
<p>I assert that, even taken in aggregate, this gives us no information about whether <i>any</i> of the soldiers have been taking drugs.</p>
<p>50% of the true "yes" answers are changed to "no", but 50% of the true "no" answers are changed to "yes".
This means 50% of all our answers are "yes", regardless of how many were "yes" before being changed.</p>
<p>Don't believe me? Imagine if every soldier has been taking drugs: 50% of them flip heads and write "yes", 50%
flip tails and write "no". This is exactly the same result, given in the story, as we'd get if none of the soldiers have been taking drugs!</p>
<p>Now imagine if 20% of soldiers have been taking drugs: 10% of the soldiers (half the drug-takers) flip heads and write "yes", 10%
of the soldiers (half the drug-takers) flip tails and write "no", 40% of the soldiers (half the non-drug-takers) flip heads
and write "no", 40% of the soldiers (half the non-drug-takers) flip tails and write "yes". 10% + 40% = 50%, for both "yes" and "no".</p>
<p>As long as each soldier inverts his response with 50% probability, we get half "yes" and half "no", regardless of how many soldiers have actually been taking drugs.</p>
<p>So while the story is quite fun and might seem to make sense, it doesn't actually work. The only way for the answer to come out 60-40
is by random chance, or if the soldiers are using biased coins, or are otherwise failing to carry out the procedure correctly.</p>
<p><b>Update 2017-07-12:</b> Aka writes:</p>
<p><blockquote>
<p>Regarding this article - the journalist probably just got the explanation wrong.</p>
<p>I believe it does work with this setup:</p>
<p><ul><li>If you get tails, tell the truth</li>
<li>If you get heads, give the "bad" answer</li></ul></p>
<p>"60% have taken drugs" is then interpreted as 50% of the people got heads, and of the remaining truth-telling 50%, 10% said yes, and 10/50==20%, so there's a 20% use rate.</p>
</blockquote></p>
<p>Which looks like it would work.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/soldiers-and-drugs.html</link>
   <guid>http://incoherency.co.uk/blog/stories/soldiers-and-drugs.html</guid>
   <pubDate>Fri, 03 Mar 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>SMS Privacy was attacked last night</title>
   <description><![CDATA[This morning I checked on the list of SMS Privacy user accounts, as I do every morning, and found that
quite a large number had been created overnight, between 22:48 and 23:10 GMT on 24th of Feb 2017. Most of them had names like:]]></description>
   <content:encoded><![CDATA[<p>This morning I checked on the list of <a href="https://smsprivacy.org/">SMS Privacy</a> user accounts, as I do every morning, and found that
quite a large number had been created overnight, between 22:48 and 23:10 GMT on 24th of Feb 2017. Most of them had names like:</p>
<p><pre><code>(select(0)from(select(sleep(6)))v)/*'+(select(0)from(select(sleep(6)))v)+'"+(select(0)from(select(sleep(6)))v)+"*/</code></pre></p>
<p><pre><code>BWfUtOFm';select pg_sleep(2); --</code></pre></p>
<p><pre><code>-1 OR 3+847-847-1=0+0+0+1</code></pre></p>
<p>which is obviously an attempt at SQL injection.</p>
<p><h3>What did they do?</h3></p>
<p>It was clearly an automated tool. It made over 12k requests over 22 minutes.</p>
<p>Apart from it being highly unethical to do vulnerability scanning on somebody else's website without permission,
it's also pretty illegal...</p>
<p>The first request was "<tt>GET /acunetix-wvs-test-for-some-inexistent-file</tt>", which points to <a href="https://www.acunetix.com/">Acunetix</a>.
The User-Agent string was:</p>
<p><pre><code>Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.21 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.21</code></pre></p>
<p>which, judging by <a href="http://stackoverflow.com/questions/35773886/xss-vulnerability">this StackOverflow post</a> is also used by Acunetix. Of
course, it could easily be another tool that is just disguising itself as Acunetix but I consider that unlikely. It
was most likely just Acunetix.</p>
<p>All of the requests went to the Tor hidden service.</p>
<p><h3>What did they find?</h3></p>
<p>I looked through the access logs to see if I could find anything untoward. There were no requests with uncharacteristically-large response
sizes, indicating there was no bulk transfer of data out of the database. There were 6 requests with a response code of 500 (Internal Server Error).</p>
<p>I get emails whenever <a href="http://mojolicious.org/">Mojolicious</a> writes anything to its error log, and I got some emails about:</p>
<p><pre><code>[Fri Feb 24 22:50:20 2017] [error] DBD::mysql::db selectrow_hashref failed: Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='</code></pre></p>
<p>This is a bit troubling. It shouldn't be possible for user input to cause errors, let alone SQL errors. It turns out that inputting
characters to the signup/login forms that exist in UTF-8 but not in latin1 caused this error, even though it was passing the username to MySQL with
a bound parameter. Surprising, although probably not exploitable.</p>
<p>I'm quite confident there are no SQL injection vulnerabilities in SMS Privacy.</p>
<p><h3>What did I do?</h3></p>
<p><a href="https://caconym.co.uk/">Matt</a> (with permission) ran <a href="http://sqlmap.org/">sqlmap</a> on the login form, and found
no exploitable inputs. This isn't a surprise.</p>
<p>To prevent the "Illegal mix of collations" error from MySQL, I have added stricter validation on the contents of usernames in both the signup
and login forms. The "correct" thing to do would be to handle UTF-8 correctly, but this was the path of least resistance.
All existing legitimate usernames are still allowed.</p>
<p><h3>Who was it?</h3></p>
<p>Since they used the Tor hidden service, I have no way to even know which IP address the attack originated from. We can only speculate on motive.</p>
<p>I think it's unlikely to be a sophisticated or well-financed attacker (e.g. a nation state) as they would presumably be a bit more subtle about it.</p>
<p>Maybe a script kiddie was just doing it for fun? Maybe a criminal was doing it to find vulnerabilities to sell?
Maybe a criminal was doing it to try to read people's messages? Maybe a customer was doing it to make sure the service is adequately secure?
Maybe it wasn't targeted, and was just an automated attack on a large number of Tor hidden services?</p>
<p>Don't know.</p>
<p><h3>Conclusion</h3></p>
<p>No harm was done. I've improved the username validation, and I'm now aware that SMS Privacy is the subject of potentially-targeted attacks, which is scary but
probably to be expected.</p>
<p>And if you want to do some security testing of SMS Privacy, that's fine, but please get permission first :).
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/20170224-smsprivacy-attack.html</link>
   <guid>http://incoherency.co.uk/blog/stories/20170224-smsprivacy-attack.html</guid>
   <pubDate>Sat, 25 Feb 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Steganographic Bitcoin seeds: Hiding cash in plain sight</title>
   <description><![CDATA[
I made a tool, stegoseed, to generate sentences which steganographically encode Bitcoin
wallet seeds, and to decode such sentences to retrieve wallet seeds. It comes with an example BIP39 seed to play with.]]></description>
   <content:encoded><![CDATA[<p>
I made a tool, <a href="http://incoherency.co.uk/stegoseed/">stegoseed</a>, to generate sentences which steganographically encode Bitcoin
wallet seeds, and to decode such sentences to retrieve wallet seeds. It comes with an example BIP39 seed to play with.</p>
<p>(Scroll down to "Instructions" if you don't care how it works, and you just want to play with it).</p>
<p><h3>Background</h3></p>
<p><h4>HD wallets</h4></p>
<p>Hierarchical Deterministic Wallets were introduced in <a href="https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki">Bitcoin Improvement Proposal 32</a> (BIP32).
Before HD wallets, Bitcoin wallet software had to store a separate private key for each payment address. HD wallets present a way to derive an unlimited
stream of private keys from a fixed-size numeric seed. This makes it a lot easier to back up a wallet without having to update the backup every time a new
address is used.</p>
<p>HD wallets also present a way to create a "watch-only" wallet: this is a different fixed-size secret
that makes it possible to derive the stream of <i>payment addresses</i> corresponding to the stream of private keys, without giving any way to determine what
the private keys are. This way you can keep a watch-only wallet of your cold storage without being able to spend it.</p>
<p><h4>BIP39 word lists</h4></p>
<p><a href="https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki">BIP39</a> introduces a way to represent numbers (e.g. BIP32 seeds) using
mnemonics. This makes it easier for humans to write down seeds, and harder to write them down incorrectly.</p>
<p>BIP39 includes <a href="https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md">word lists</a> for many different languages. Each list has
2048 words. For example, <a href="https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt">here is the English list</a>.</p>
<p>Not all combinations of words are valid because they must also encode a checksum. Typically 12 words are used to generate an HD wallet seed.</p>
<p>Ian Coleman has <a href="https://iancoleman.github.io/bip39/">a fantastic tool</a> for playing with BIP39 seeds.</p>
<p><h4>Markov Models</h4></p>
<p>A Markov model models a random system where (<a href="https://en.wikipedia.org/wiki/Markov_model">Wikpedia</a>) "future states depend only on the current
state [and] not on the events that occurred before it". In modelling sequences of words (i.e. sentences), an order-<i>n</i> Markov model can tell us, given <i>n</i> words, which words can follow,
and with what probability.</p>
<p>We can also build Markov models in 2 directions (i.e. one to model which words can go after a given word, and one to model which words can go before a given word).
This way we can choose an arbitrary word, and then use the Markov model to generate random words in the forwards and backwards direction, until we reach a
valid sentence end point and start point, respectively.</p>
<p><h3>Hiding seeds in text</h3></p>
<p>Given these primitives, we can now generate sentences which encode HD wallet seeds: take as input a text corpus, a BIP39 word list, and a BIP39 mnemonic seed. Build a
2-directional Markov model of the text corpus, but specifically do not allow it to generate any BIP39 words. Now, for each word of the mnemonic seed, start from
that word, and use the Markov models to generate words forwards and backwards until we have a complete sentence. Concatenate the sentences together and give output.</p>
<p>Our output is now a series of sentences which contain the BIP39 words given in the input, in the correct order, and do not contain any other BIP39 words. We can
simply remove all non-BIP39 words to retrieve the original seed.</p>
<p><a href="http://incoherency.co.uk/stegoseed/">Stegoseed</a> comes with a pre-generated 2-directional order-1 Markov model of quite a large
text corpus of news articles (it's a 7M Javascript object), and the English BIP39 word list.</p>
<p><h3>Instructions</h3></p>
<p><h4>1.) You have a BIP39 seed and want to hide it in some randomly-generated text</h4></p>
<p>Paste your BIP39 seed in the "Hide" box and click "Stego". You'll get a randomly-generated piece of text. If you don't like it, click "Stego"
again to get another. This is quick and easy.</p>
<p>The generated text is quite nonsensical, but without the BIP39 words highlighted, it would be hard for a human to realise what it is encoding.</p>
<p><h4>2.) You have a piece of text and want to retrieve the BIP39 seed</h4></p>
<p>Paste your text into the "Unhide" box and click "Unstego". You'll get the BIP39 seed. This is quick and easy.</p>
<p><h4>3.) You have a BIP39 seed and want to hide it in some existing piece of text</h4></p>
<p>Paste your existing text into the "Unhide" box and click "Unstego". You'll be given a list of BIP39 words that
appear in your text. You need to go through and modify the text to remove every single one of them. Do this, and click "Unstego" again, until there are no
longer any BIP39 words.</p>
<p>Now take your BIP39 seed and find places to insert those words into the text without inadvertently inserting other BIP39 words. Repeat until done. This
is neither quick nor easy and honestly I can't recommend trying it.</p>
<p><h3>Example</h3></p>
<p><a href="http://pastebin.com/MAVJBm16">This pastebin</a> contains a rewording of <a href="http://www.bbc.com/news/health-39040146">this BBC News article</a>
about life expectancy. I manually removed all of the existing BIP39 words from the article, and then inserted the words corresponding to
my own BIP39 wallet seed. It contains some funds as a prize for whoever sweeps it first (<b>update:</b> this has been taken).</p>
<p><h3>Conclusion</h3></p>
<p>The text generated by stegoseed encodes exactly the same information as the original seed, and should be treated with equal care. You wouldn't go pasting your
wallet seed around the Internet and expect not to have your money stolen, so don't do it just because the seed is hidden steganographically.</p>
<p>But it might help you if you have to hide your seed on paper in your house and you don't want a casual burglar to guess what it is. Or
if you have to carry it on your person through an area where you might be searched by somebody who might want to steal your money.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/steganographic-bitcoin-seeds.html</link>
   <guid>http://incoherency.co.uk/blog/stories/steganographic-bitcoin-seeds.html</guid>
   <pubDate>Wed, 22 Feb 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Precautions for generating Bitcoin QR codes</title>
   <description><![CDATA[A couple of people have been asking me to add QR codes to the payment page on SMS Privacy.
I'd been putting it off for a while because I didn't want to do it in a way that opens up avenues for exploitation.]]></description>
   <content:encoded><![CDATA[<p>A couple of people have been asking me to add QR codes to the payment page on <a href="https://smsprivacy.org/">SMS Privacy</a>.
I'd been putting it off for a while because I didn't want to do it in a way that opens up avenues for exploitation.</p>
<p>The first thing you want to do if displaying Bitcoin QR codes (and, indeed, Bitcoin addresses <i>at all</i>) is to
serve them over HTTPS. Otherwise it is pretty easy for a man-in-the-middle to simply replace your addresses with their own, regardless
of how otherwise-secure your web service is.</p>
<p>The second, and less obvious, thing is to make sure that you don't make it possible for a malicious attacker
to determine whether a given Bitcoin address belongs to a user of your site.</p>
<p>If your solution is along the lines of "run qrencode when we generate the address, and put the PNG in <tt>public/qr-code/$address.png</tt>"
then you make it trivially easy for an attacker, given a Bitcoin address, to determine whether or not it belongs
to your web service (just test for the existence of the PNG).</p>
<p>If your solution is along the lines of "provide an API endpoint to generate QR codes at /qr-code?address=..." then this can work.
But, crucially, it is only safe if you <i>don't</i> do too much validation of the input address. As soon as you start
rejecting addresses that don't belong to your site, you again make it easy for an attacker to determine whether
or not a Bitcoin address belongs to your service. Even if you still return a QR code either way, doing validation opens you
up to timing attacks, and doesn't gain you anything.</p>
<p>Also, if you do that, make sure you <i>don't</i> cache the generated PNGs, otherwise you are again opened up to timing attacks (QR codes
that belong to users will be cached, and QR codes that don't will not).</p>
<p>If your solution is along the lines of "provide an API endpoint to generate the current user's QR code at /qr-code", then I
can't see any way to do this wrong. It doesn't provide any mechanism for an attacker to query you with arbitrary addresses.
All anybody can do is retrieve the QR code for their current payment address. This is safe even if you cache the generated PNGs.</p>
<p>This last solution is what I did for SMS Privacy.</p>
<p>I'd be interested to hear if other people have other concerns or improvements.</p>
<p><b>Update 2017-11-27:</b> An anonymous reader writes to suggest generating
the QR code as an SVG and inlining the SVG tags to display it on the page. This way no API endpoints need to be created at all, and displaying
a QR code is functionally almost equivalent to displaying the address in text.
I think that's a great idea, and it would work almost as
well by generating PNG files and inlining them with data URIs, e.g. <tt>&lt;img src="data:image/png;base64,...</tt>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/bitcoin-qr-code-precautions.html</link>
   <guid>http://incoherency.co.uk/blog/stories/bitcoin-qr-code-precautions.html</guid>
   <pubDate>Wed, 15 Feb 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Encrypted email is still a pain in 2017</title>
   <description><![CDATA[Today I sent an email to somebody who specified that he "prefers GPG mail". I didn't have any GPG set up, so I
just sent a normal email, which worked perfectly well. But it made me look in to GPG, and this is what I learnt...]]></description>
   <content:encoded><![CDATA[<p>Today I sent an email to somebody who specified that he "prefers GPG mail". I didn't have any GPG set up, so I
just sent a normal email, which worked perfectly well. But it made me look in to GPG, and this is what I learnt...</p>
<p><h3>Act I: Try to set it up on my own</h3></p>
<p>I DuckDuckGo'd for keywords like GPG, Thunderbird, Linux, and found that the tool I need to install is
<a href="https://enigmail.net/index.php/en/">Enigmail</a>. It is a Thundebird add-on that handles GPG (or PGP? or
OpenPGP? are they all the same?).</p>
<p>I installed it and restarted Thunderbird. An Enigmail setup wizard appeared. "Excellent," I thought, "this must
be just what I need". I selected the recommended configuration for new users, and Enigmail started generating a key (or so I thought!). It said it
may take "several minutes" to generate the key. No problem.</p>
<p>10 minutes later I checked back and found that the progress bar had not advanced at all. I DuckDuckGo'd a bit and found
that Enigmail <a href="https://sourceforge.net/p/enigmail/forum/support/thread/b9d07faf/">has a bug</a> where it
doesn't drive <tt>gpg</tt> correctly and therefore hangs forever instead of generating keys. What a shitfest.</p>
<p><h3>Act II: Enlist the help of an expert</h3></p>
<p><a href="https://charlie.ht/">Charlie</a> recommended using the <tt>gpg</tt> command-line tool directly, which I tried
next.</p>
<p><tt>$ gpg --gen-key</tt></p>
<p>After entering my name and email address, and opting for the recommended key length and expiration,
I was told "You need a Passphrase to protect your secret key". But it didn't ask me to <i>input</i> a passphrase, and
when I tried to, it was echoed back; unusual for a passphrase. I hit enter and nothing
happened for about 20 seconds. What a shitfest.</p>
<p>To cut a long story short, <tt>gpg</tt> eventually popped up a GUI box, but I accidentally skipped it because I was hammering the
enter key trying to get it to do something...</p>
<p>So I tried again. This time I was prepared for the GUI, which this time loaded substantially faster.
I entered a passphrase and <tt>gpg</tt> started generating my key, and eventually it was done. Golden.</p>
<p>I was informed that <tt>gpg</tt> had checked the trustdb and it needed 3 marginals and 1 complete, and that my trust
was 0 each for <tt>-</tt>, <tt>q</tt>, <tt>n</tt>, <tt>m</tt>, and <tt>f</tt>, and 1 for <tt>u</tt>. There might
also have been something about a +4 defence bonus against melee attacks.</p>
<p>I went back into Enigmail and this time selected the Advanced option in the setup wizard. It asked me
for the path to my public
key file and my private key file. Unfortunately, despite the wealth of obscure stats I'd been given, <tt>gpg</tt> had
not told me the paths to the key files, so I had to go hunting. What a shitfest.</p>
<p>The Enigmail file selection dialogue was looking for <tt>.gpg</tt> files, which was a helpful clue. I found 3 under <tt>~/.gnupg</tt>: <tt>pubring.gpg</tt>,
<tt>secring.gpg</tt>, and <tt>trustdb.gpg</tt>. I guessed that <tt>pubring.gpg</tt> was the public key file and <tt>secring.gpg</tt>
was the private key file, which turned out to be correct but wasn't as obvious as it could have been.</p>
<p><h3>Act III: Put it to use</h3></p>
<p>From here it worked pretty flawlessly. I tried to email Charlie by typing his email address in the box. Enigmail told me it didn't
know of a key for him, but I could look him up in a key server (?) which it had a GUI for. I did this, found him quickly, and sent an email.
It arrived, and he was even able to send an encrypted email back to me.</p>
<p>So I now have an encrypted email setup. Although at 2 hours, it took me about 1 hour and 55 minutes more than I expected. I still
need to participate in a key-signing party of some sort, which I am looking forward to.</p>
<p>In the absence of having my key signed in a key server (?), I think you can retrieve my key by copying and pasting the text at the
bottom of this post. I generated it with <tt>gpg --export -a "James Stanley"</tt>.
I think you can import it into your client by saving it to a file (e.g. <tt>jes.key</tt>) and running <tt>gpg --import jes.key</tt>.</p>
<p>If that doesn't do the trick, how you are <i>supposed</i> to import it is anyone's guess.</p>
<p><h3>Conclusion</h3></p>
<p>Encrypted email is nothing new (PGP was initially released in 1991 - 26 years ago!), but it <i>still</i> has a huge barrier to entry
for anyone who isn't already familiar with how to use it.</p>
<p>I think my experience would have
been better if Enigmail had generated keys out-of-the-box, or if <tt>gpg</tt> (a.) agreed with Enigmail on nomenclature (is it a secring or a private key?)
and (b.) output the paths of the files it had generated. My experience would have been a lot worse had I not been able to call on
the help of somebody who already knows how to use it.</p>
<p>Please send me an encrypted email if you can work out how to do it. And if I can work out how to do it, I'll send you an encrypted reply.</p>
<p>I am "James Stanley" and "james@incoherency.co.uk", and this is my key:</p>
<p><b>Update:</b> The key below was initially wrong. I had some <tt>&lt;h2&gt;</tt> tags which I changed to <tt>&lt;h3&gt;</tt> with search
and replace. This replaced the "h2" in the third line of the key with "h3" and therefore broke it. My bad.</p>
<p><pre><code>-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1</p>
<p>mQENBFihmuQBCACzmsZ8DTjmcsoAoeFwrFVGn35kalJGFuIW5q7yIB3EzaTso48j
xOcFLSXl25BmonT3wDj5RdnA0ONgo9Gtrq34dweAHXyfHwkLdy1Nz/lkLMakZ8xw
ng3toh2d7Ri/8o6tTaCum/cKDjeDRWxADz5a/rtM8DBt+8OJyhd9rhObxJKW5L8m
LdO5CWrGb8Fr1yIb9LYUiCMfzuirPqYVGfYiIG/OI4V/wGFvHt7fq1ybBCMTEiVT
UGXDedyNLOsAjTqx9bN/i2CGPMMKqsqFSkPfAa3BfXQrqnubnTCFTV696U41GxtI
guN0II3mhNc2s20Z8Bq7/H3X6dc3fspma4gLABEBAAG0J0phbWVzIFN0YW5sZXkg
PGphbWVzQGluY29oZXJlbmN5LmNvLnVrPokBOAQTAQIAIgUCWKGa5AIbAwYLCQgH
AwIGFQgCCQoLBBYCAwECHgECF4AACgkQWKuFKgoswTcNhAf9HfiZnEa7Dlz9iriH
MlqDzmgk0pQf3Ja9PZOw9wJhUxlFsjjxvkbdV7dcBprd+ukOby01k0A57e89/Wb5
Xn/Kq7efkWJwXCb1UAj7DHYYfIdlvPslMSLp1WAqFH6GC6JSBTTsPdDmvyqhu0pP
XNzvURPtOQzMMjfR/r3jQNoU9P+l0LFZpq3Cfn41/oR396S+wiwk2TXC5On9Bg7d
SiGAOBA8kwaYDFdX3TmGzSgQ4EkNgfewi/S6UImdPVetGfT4xzNkpmG/Nw4y2LHm
L4yn9LqIZOqrrWyRU1eU/41E5+OXEDkQrkTPdD7VodwnNqDZ5M9BSuCHY0bPP6bq
rRSPdbkBDQRYoZrkAQgAmLl0AAd5zH/pzGM/ZfNKWkO3aKmSCkw/kdslZJm2werq
fI7NEK2PyXZPn5hGv9LjQaSi/wC+S4iAtHMvYUb2LEY8Jrtf55sI9mTSWbCKEji4
JpOmpSzB6ynydn/RyrvinWyVPNiVzai9cJTyh5rBrnZNIA9eYkWuk4RVCZwfCQzj
vtv+tl5qS2V05S0TfYkdGqJ5TiyIguNz22TpxmwhIdEJBQVGFIT6OW+DWqME/ufT
av6uonpXF2pW2QaSao5m1R9znJUbT+3HHnc8Y4nwOQjVjriD/Tzw4V6LFRgki7zN
+ySSJmvVbBvlYqpjQgjzORLlm6RPPBZICkKu2LN4OwARAQABiQEfBBgBAgAJBQJY
oZrkAhsMAAoJEFirhSoKLME3AIgH/1MSecs1CQDbDU561CKZczmPWpyqQ8B/D6JL
WJsYsROuu+KPYbqs12pmlu/69H24DWt2stlAA6kek3t4KiaaZrtX8or6zm16hd4n
04Oi+oE2bn7AYjvMql6FJv5RwQnHzazhNX79DPA6b16dPotEtmo9MALp5ZV9bcL7
SnnW+60H0Dh6cSzFdlBW3UGXxNzRjQGZ5GkTtLKn7rSqB5qw3PlDsRSezT6R7E28
21ozqazzoo4RVEkHfQpwXslPJuWOfOKnKYLr+CuCkaUDlbj2SLhPkAHFthCFFXqU
7AaSswbvNrtQyUv2W2zps9FO2dTrLMmj81K4XT24GDzqmpWGqhs=
=KTV8
-----END PGP PUBLIC KEY BLOCK-----</code></pre>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/gpg.html</link>
   <guid>http://incoherency.co.uk/blog/stories/gpg.html</guid>
   <pubDate>Mon, 13 Feb 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I bought an extremely cheap 3d printer and it's great</title>
   <description><![CDATA[I had a look on eBay last week to see what sort of price 3d printers are going for
these days, and was surprised to find some on offer for &pound;150. At that price it's
obviously not going to be very good, but should be fun anyway.]]></description>
   <content:encoded><![CDATA[<p>I had a look on eBay last week to see what sort of price 3d printers are going for
these days, and was surprised to find some on offer for &pound;150. At that price it's
obviously not going to be very good, but should be fun anyway.</p>
<p>I placed my order on Thursday.</p>
<p><img style="border: solid 1px #aaa" src="https://img.incoherency.co.uk/1369"></p>
<p>Over the weekend I played around in <a href="http://freecadweb.org/">FreeCAD</a> and designed a wheel and some mounts
to keep my <a href="https://incoherency.co.uk/blog/stories/hidden-bookcase-door.html">hidden bookcase door</a> from sagging.</p>
<p><img width="300px" src="https://img.incoherency.co.uk/1363"></p>
<p>The printer arrived late on Monday and I began assembling it. The printer came partially-assembled,
which is more than I expected. However, it did not come with any instruction booklet. It did have
a CD but I have no way to read a CD. It is likely the CD had a PDF of instructions.</p>
<p>I briefly Googled for instructions but they were no use. Probably for a different printer. So I
assembled it without instructions, and it went surprisingly well. Except the screws are really
small and fiddly. That's OK though.</p>
<p>My first print didn't go too well.</p>
<p><img width="300px" src="https://img.incoherency.co.uk/1367"></p>
<p>There is some issue with the extruder where it <a href="https://www.reddit.com/r/3Dprinting/comments/5q2cy9/extruder_clicking_and_not_turning/">starts
clicking and stops extruding</a>, particularly at high speeds. I turned the speed way down, tried to clean the nozzle, rejigged some of the
electrical connectors, and made sure to give the extruder a bit of help if it started clicking, and got some pretty decent prints:</p>
<p><img width="300px" src="https://img.incoherency.co.uk/1368"></p>
<p>The surface finish is poor and I still have to babysit the machine to make sure it is extruding properly. Also it is quite slow
because the speed is so far down. For example each of these parts took over an hour to print.</p>
<p>Overall I am delighted with the machine. At &pound;149 it's a steal. Way better than I could have expected. I am
excited to design more plastic parts.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/3d-printer.html</link>
   <guid>http://incoherency.co.uk/blog/stories/3d-printer.html</guid>
   <pubDate>Wed, 25 Jan 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Why minimum wage is bad, illegal immigrants are good, and ticket scalping is fine</title>
   <description><![CDATA[At first glance these three topics might seem unrelated, but the same basic argument of supply and demand applies in each case.]]></description>
   <content:encoded><![CDATA[<p>At first glance these three topics might seem unrelated, but the same basic argument of supply and demand applies in each case.</p>
<p><h2>The existence of a minimum wage is bad</h2></p>
<p>The existence of a minimum wage is telling people "if you're not worth at least this much, you're not allowed to work at all".
More generally, it is preventing consenting adults from engaging in mutually-beneficial transactions,
and preventing businesses that rely on cheaper labour from being able to operate profitably, putting them out of business, and leaving the staff unemployed.</p>
<p>Nobody would credibly argue in favour of a minimum price for a packet of crisps. And if I can produce crisps that I'm willing
to sell more cheaply than anyone else, then everyone benefits if I am allowed to do so. I benefit: I sell my crisps
at a profit. My customers benefit: they get cheaper crisps. Most other businesses benefit: my customers now
have more money left over to buy their things. Everyone's a winner, except the other crisp suppliers who have now
been out-competed. Good.</p>
<p>Identical logic refutes the existence of a minimum wage.</p>
<p><h2>The presense of illegal immigrants is good</h2></p>
<p>(Although the illegality of their presence is decidedly <b>not</b> good: free people ought to be able to travel
the world freely. But that's a rant for another day.)</p>
<p>I recently watched <a href="http://www.bbc.co.uk/iplayer/episode/p04lxtcz/illegal-job-centre">a documentary on BBC Three called "Illegal Job Centre"</a>. The presenter, in a very solemn tone,
reports on the goings-on of some people who are working in the UK illegally. The reaction this is supposed to
elicit is clearly somewhere between "oh gosh, how awful" and "this must be stopped".</p>
<p>But I don't think a rational analysis of the facts leads to anything but a positive conclusion.</p>
<p>The backstory is that the illegal immigrants hang around outside the likes of Wickes and Buildbase, waiting for a building contractor to offer
them a job labouring for the day. They receive less pay than British workers would receive for doing the same work.
They live in houses shared with upwards of 20 people, from which the landlords collect comparatively high rents.</p>
<p>And I think that's great: the immigrants get work that they otherwise wouldn't. The builders get labourers more cheaply than
they otherwise would. The immigrants get accommodation more cheaply than they otherwise could. The landlords get
more rent than they otherwise could. Everyone's a winner, except the British labourers who have now been
out-competed. Good.</p>
<p><h2>Ticket scalping is fine</h2></p>
<p>A friend of mine was recently telling me about "ticket
scalping". Ticket scalping is where a "scalper" buys up as many tickets as he can, as soon as they come on sale,
and then sells them to legitimate fans at some higher price than he initially bought them for.</p>
<p>The argument against this is something like: "it harms the fans, because now they have to pay more money to get the tickets".</p>
<p>Apart from the fact that I don't think a ticket seller has any right to tell people what they can and can't do with the tickets
that they've purchased at the going rate, I don't think ticket scalping <i>does</i> harm the fans. In fact, I think
the emergence of a mature secondary market only benefits the fans.</p>
<p>Assuming the gig is sufficiently popular, and has a finite number of tickets, there will always be more people who
want to go than are able to get a ticket. 2001 people can't have a ticket each if there are only 2000 tickets.</p>
<p>So whether there are ticket scalpers or not, somebody is going to miss out. In the absence of ticket scalpers,
whoever gets in quickest gets the ticket, and that's the end of it. But if ticket scalpers are able to buy some
of the early tickets, and are able to resell them at a higher price, then it is easy to decide which of the 2001 people
wants the tickets least. Whoever is willing to pay the least amount of money for a ticket doesn't get a ticket,
and everyone else does.</p>
<p>I don't see this as at all unfair. I don't see it as any different to the way any other scarce resource is
allocated: whoever is willing to pay the most to acquire it, acquires it.</p>
<p>The "official" ticket sales company sells all of their tickets at the price they wanted. The ticket scalper
makes a profit. Fans who are willing to pay fair market value for tickets are able to ensure they can get a ticket.
Everyone's a winner, apart from the fans who were not willing to pay fair market value for tickets. Good.</p>
<p>And if the original company is so sure that the tickets are worth more than what they're charging, they should be charging more. If they're not
sure they're worth more, they should be happy to sell them at the price they have decided is fair.</p>
<p><h2>But that's just ruthlessly capitalist</h2></p>
<p>Capitalist? Yes. But that's not a bad thing. Ruthless? I don't know. I don't think it's <i>ruthless</i>, so much as it
is merely <i>fair</i>.</p>
<p>All of this emerges naturally as a result of individuals maximising their own utility in a free
market, and I think any moves to prevent that outcome lie somewhere between misguided and outright harmful.</p>
<p>So here's my prescription to governments of the world: abolish the minimum wage, abolish all restrictions on the travel
and occupation of immigrants, and abolish laws preventing ticket scalping.</p>
<p>I understand that a large proportion of the population disagrees with my logic here, but I can't for the life of me figure out why.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/supply-and-demand.html</link>
   <guid>http://incoherency.co.uk/blog/stories/supply-and-demand.html</guid>
   <pubDate>Tue, 17 Jan 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The Game Theory Case for Bitcoin</title>
   <description><![CDATA[
During a period of only 4 hours today, the value of Bitcoin dropped by more than 30% (8888 CNY down to 6000 CNY).
This sparked some discussion at work about what it is that makes Bitcoin worth anything in the first place.]]></description>
   <content:encoded><![CDATA[<p>
During a period of only 4 hours today, the value of Bitcoin dropped by more than <b>30%</b> (8888 CNY down to 6000 CNY).
This sparked some discussion at work about what it is that makes Bitcoin worth anything in the first place.</p>
<p>For me, the value proposition of Bitcoin is that it can not be devalued by any government or central bank attempting
to stimulate (read: manipulate) the economy.</p>
<p>You might argue that being able to devalue the currency is <i>good for the economy</i>. That may be so, and it may not.
<a href="http://www.salientpartners.com/epsilon-theory/magical-thinking/">W. Ben Hunt argues</a>
that adjusting interest rates to stimulate the economy does not help: that it's just like trying to make things
look the way they looked during the good times in hopes that the good times will return.</p>
<p>Regardless, my argument is that it doesn't matter whether it is "good for the economy" or not: devaluation of
a currency is bad for the people <i>holding</i> that currency.
Given a choice between a currency that is regularly devalued and one that can not be devalued, individuals should rationally choose to store their wealth in the one that can not be devalued.</p>
<p>Positive interest rates mean fiat currency is almost always being devalued (the US Dollar inflated over 2000% over the last 100 years).
And you're no better off under negative interest rates: they just take your money while it's in the bank.</p>
<p>Bitcoin defends against both of those cases. This brings us to the logical conclusion that,
all else being equal, <b>rational actors will move their wealth from fiat currencies to Bitcoin so that
it is not inflated away from them.</b></p>
<p>Of course, all else is not necessarily equal...
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/game-theory-bitcoin.html</link>
   <guid>http://incoherency.co.uk/blog/stories/game-theory-bitcoin.html</guid>
   <pubDate>Thu, 05 Jan 2017 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Secrets of the Medtronic MyCareLink Patient Monitor</title>
   <description><![CDATA[I have acquired a "Medtronic MyCareLink Patient Monitor 24950" and have been
playing with it a little this weekend. It looks like this:]]></description>
   <content:encoded><![CDATA[<p>I have acquired a "Medtronic MyCareLink Patient Monitor 24950" and have been
playing with it a little this weekend. It looks like this:</p>
<p><a class="img" href="https://img.incoherency.co.uk/1354"><img src="https://img.incoherency.co.uk/1354/thumb"></a></p>
<p>The device is no longer needed owing to the unfortunate death of its previous owner. Before giving
it to me, people did <i>try</i> to return the device to the NHS but they did not want it and
didn't seem to know what to do with it. So, game on.</p>
<p>I initially had no idea what the device was for. When you turn it on, it eventually
gives a graphical hint that you should hold the handheld piece up to your chest:</p>
<p><img src="https://img.incoherency.co.uk/1353"></p>
<p>I gather it is some sort of pacemaker monitor. In any event, the light did not turn
green when I held it up to <i>my</i> chest. (I do not have a pacemaker).</p>
<p>(<b>Update 2016-12-04:</b> <a href="https://news.ycombinator.com/item?id=13102057">alphaoverlord on HN points out</a> it's for an "implantable loop recorder"
for heart monitoring, and not for a pacemaker.)</p>
<p>I opened up the base unit, a task complicated by the use of some unusual
5-pointed security screws (fortunately they were made of your standard
Chinesium metal and quickly succumbed to my 6-pointed bit). Inside, I found a Huawei USB GSM
dongle, with a SIM card inside that.</p>
<p><a class="img" href="https://img.incoherency.co.uk/1355"><img src="https://img.incoherency.co.uk/1355/thumb"></a></p>
<p>I also found a suitably-enticing MicroSD card.
The only "MicroSD card reader" I have is a Garmin VIRB video camera. So I inserted the MicroSD card
into my Garmin VIRB video camera, which I plugged into the laptop.</p>
<p>The MicroSD card has 4 partitions. One is a FAT-formatted boot partition which seems to contain <a href="http://www.denx.de/wiki/view/U-Boot">U-Boot</a>
(and now also some Garmin-related nonsense thanks to my MicroSD card reader).</p>
<p>The other 3 partitions are all ext3.  Two of them contain a bunch of files named things like
<tt>ECRYPTFS_FNEK_ENCRYPTED.FWYdhbehxfVBr-TWPN4xB6NkyyaRqzxo8mZKbXH2s0PdbqIxnZvdHmm1ok--</tt>
(apparently <a href="http://ecryptfs.org/">eCyryptfs</a>-encrypted), but the final
partition is more promising: it contains a Linux root filesystem. Some investigation revealed that this is specifically
a <a href="http://www.mvista.com/">MontaVista</a> Linux system.</p>
<p>I examined a few binaries and found that the device has an ARM CPU, not
too surprising. I was more fascinated with what might be on the encrypted partitions.
Obviously, since the device boots and runs without
asking for a password, the decryption credentials must be in here <i>somewhere</i>.</p>
<p>I grepped the root filesystem for interesting keywords (like "ecryptfs") and came
across a script in <tt>/etc/init.d/startupservices</tt> containing, among other things:</p>
<p><pre><code>ENCRYPT_DIR=/usr/sbin
ENCRYPT_UTIL=eis3920
<i>...</i>
echo "Try for Decrypting Partition..."
# Add mount utility here
$ENCRYPT_DIR/$ENCRYPT_UTIL 1>/dev/null 2>&amp;1</code></pre></p>
<p>Aha! So this mysteriously-named <tt>/usr/sbin/eis3920</tt> program is responsible for the decryption.
<tt>eis3920</tt> is an ARM binary, but running <tt>strings</tt> on it came up
with some items of interest:</p>
<p><pre><code><i>...</i>
<b>/sys/devices/platform/omap/omap_i2c.2/i2c-2/2-0057/eeprom</b>
%s%s%s%s%s
/home/root
.ecryptfs
sig-cache.txt
ecryptfs_fnek_sig=
%s%s%s%s%s%s%s%s%s%s%s%s
<b>mount -t ecryptfs </b>
 -o 
<b>key=passphrase:passwd=</b>
,ecryptfs_cipher=aes,
ecryptfs_key_bytes=16,
ecryptfs_passthrough,
no_sig_cache,
ecryptfs_enable_filename_crypto=y,
<i>...</i></code></pre></p>
<p>Highlighted in bold, we can see a.) that it has something to do with an eeprom device,
b.) that it does indeed appear to mount some filesystem with ecryptfs, and c.) unfortunately
the password is not present. The password is most likely hidden in the eeprom. Darn!</p>
<p>I am not enough of a hardware hacker to be able to even identify the eeprom on the circuit board,
let alone interact with it and retrieve its contents.</p>
<p>Fortunately I don't have to! On this MicroSD card I have a Linux system that is already setup to run on this
hardware, and includes a tool that will conveniently read the password from the eeprom and pass it to
<tt>mount</tt>. So I moved <tt>/bin/mount</tt> to <tt>/bin/mount.orig</tt> and wrote a script in
<tt>/bin/mount</tt> that logs its arguments to the filesystem before calling <tt>mount.orig</tt>:</p>
<p><pre><code>#!/bin/sh
echo "$@" >> /mount-args.log
mount.orig "$@"</code></pre></p>
<p>Then I put the MicroSD card back in the Medtronic, switched it on, waited for it to boot up, switched it off
again, put the MicroSD card back in the Garmin again, and plugged the Garmin back into the laptop again.</p>
<p>Success! On the first try, no less. <tt>/mount-args.log</tt> now contained what I wanted to see. Most
of the mount invocations were missing because the root filesystem is initially brought up readonly, but I
did get:</p>
<p><pre><code>-t ecryptfs /opt/ /opt/ -o key=passphrase:passwd=<b>REDACTED</b>,ecryptfs_cipher=aes,ecryptfs_key_bytes=16,ecryptfs_passthrough,no_sig_cache,ecryptfs_enable_filename_crypto=y,ecryptfs_fnek_sig=29b67aadf6b84ddc
-t ecryptfs /data/ /data/ -o key=passphrase:passwd=<b>REDACTED</b>,ecryptfs_cipher=aes,ecryptfs_key_bytes=16,ecryptfs_passthrough,no_sig_cache,ecryptfs_enable_filename_crypto=y,ecryptfs_fnek_sig=29b67aadf6b84ddc</code></pre></p>
<p>Both <tt>/data</tt> and <tt>/opt</tt> use the same password (though it looks reasonably strong).
With the password recovered, I was able to mount the encrypted partitions on my laptop, to peruse at my leisure. Boom.</p>
<p>I did not find any evidence of patient data stored on the device, even in the encrypted partitions. All I could
find was the binaries and data for the Medtronic application, and it's not clear to me why it even needs to be encrypted.</p>
<p>From poking around I learnt a little about the architecure of the software. It seems to be a C# application that
has been ported from Windows, consisting of a small handful of microservices. Apart from how distasteful it is
to be running a C# Windows application on an embedded Linux device, it seems fairly well designed. </p>
<p>To send the data back to Medtronic it speaks to <tt>https://mgus.medtronic.com</tt> and
<tt>https://mgnl.medtronic.com</tt> (which correspond to the US and the Netherlands, respectively).
These servers present self-signed SSL certificates, but the certificate is bundled with the
application and there is evidence that it checks it - arguably a <i>more</i> secure setup than
relying on CA verification, especially given the <a href="https://wiki.mozilla.org/CA:WoSign_Issues">recent WoSign shenanigans</a>. They also use HTTP Basic auth, and
the credentials are again stored in the eeprom. One of the microservices is called <tt>NVMemoryD</tt> and
exposes access to the eeprom over DBus.</p>
<p>I took a look at <tt>/proc/cpuinfo</tt> and <tt>/proc/meminfo</tt> and learnt that it has an
"ARMv7 Processor rev 2 (v7l)", and 128M of RAM. It might be interesting to use it like a Raspberry Pi if you could
get some sort of interactivity. My current process for getting code executed on this device is <i>far</i> too tedious so I probably
won't be using it a lot. Of course, with arbitrary root code execution, doing anything you want is "merely"
an engineering exercise. So it ought to be possible to get a console on the display and use a USB keyboard. But
I don't know that I have the appetite for that kind of project.</p>
<p>I briefly experimented with the GSM dongle - I wasn't able to make much use of it. I couldn't
even ping anything. I haven't checked whether this SIM can only talk to Medtronic's servers, or if
it has ran out of credit and can't be used at all.</p>
<p>I did take a look inside <a href="https://fccid.io/LF524955">the handheld device</a> as well. The FCC ids on the sticker show that it has some
<a href="https://fccid.io/T7V1315">Bluetooth hardware</a> inside, and I also found a large coil that seems to be some sort of NFC transceiver (?).
From this I gather that the handheld device reads information off the pacemaker over NFC, and then transmits it
to the base unit over Bluetooth, which then sends it to the HTTPS service over GSM, which makes
it available to the patient's doctor or other medical staff. A chain of devices with increasing communications range and power
requirements...</p>
<p>Anyway, that's what I've learnt about the Medtronic MyCareLink Patient Monitor. It was enjoyable to
poke around a piece of medical equipment, as I have never had the chance before.
Security-wise, perhaps if they had epoxied the MicroSD card to the board that would
have kept <i>me</i> out, but a sufficiently-motivated attacker with hardware access will always succeed.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/medtronic-mycarelink.html</link>
   <guid>http://incoherency.co.uk/blog/stories/medtronic-mycarelink.html</guid>
   <pubDate>Sun, 04 Dec 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Please stop making popup menu bars</title>
   <description><![CDATA[There is a trend on the web at the moment to make menu bars that disappear when you scroll
down, and reappear when you scroll up. 
This article
encourages everybody to do it because "menus aren't pretty" and screen space is at a premium
on mobile devices.]]></description>
   <content:encoded><![CDATA[<p>There is a trend on the web at the moment to make menu bars that disappear when you scroll
down, and reappear when you scroll up. 
<a href="https://medium.com/@mariusc23/hide-header-on-scroll-down-show-on-scroll-up-67bbaae9a78c">This article</a>
encourages everybody to do it because "menus aren't pretty" and screen space is at a premium
on mobile devices.</p>
<p>Well, I don't care if menus aren't pretty, and I'm not on a mobile device. But sometimes I
accidentally scroll too far, and then scroll back up to bring the text back into view.
Except as soon as it comes back into view, the menu bar slides down and covers it up! How is
that helpful?!</p>
<p>I've been annoyed about this trend for quite some time, but I've now seen too much of it to stay
quiet in good conscience. So, here's my plea:</p>
<p>Please, everybody, <b>stop</b> making popup menu bars.</p>
<p>Thank you for reading.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/please-stop-making-poup-menu-bars.html</link>
   <guid>http://incoherency.co.uk/blog/stories/please-stop-making-poup-menu-bars.html</guid>
   <pubDate>Fri, 02 Dec 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How (and why) to accept Bitcoin payments yourself (without running a full node)</title>
   <description><![CDATA[
Accepting Bitcoin payments for an online service can be daunting at first
(I worked out how to do it, for SMS Privacy,
a couple of months ago). What I describe is not the only way to accept Bitcoin payments - it's not even the
best way to accept Bitcoin payments - but it works for me. And it might work for you, too.]]></description>
   <content:encoded><![CDATA[<p>
Accepting Bitcoin payments for an online service can be daunting at first
(I worked out how to do it, for <a href="https://smsprivacy.org/">SMS Privacy</a>,
a couple of months ago). What I describe is not the only way to accept Bitcoin payments - it's not even the
<i>best</i> way to accept Bitcoin payments - but it works for me. And it might work for you, too.</p>
<p><h3>Why handle payments yourself?</h3></p>
<p><blockquote><i>If you control the Bitcoin keys, it's your Bitcoin; if you don't control the Bitcoin keys, it's not your Bitcoin.</i><small><a href="https://www.youtube.com/watch?v=F12lpqnug-0">Andreas Antonopoulos</a></small></blockquote></p>
<p>Third-party Bitcoin payments services typically take a 1% fee (<b>update 2016-11-12:</b> this is not accurate). This is better than credit card processing (and without the risk of fraud or chargebacks),
but we can do better. Using a payments service also means trusting that service (a) not to steal your money, and (b) not to
<i>lose</i> your money.</p>
<p>But mainly it means <i>asking permission</i>: if the payments service doesn't like you, or you can't provide enough
identity verification, or you flag up the wrong security check, they can simply deny you service. A large part of
the attraction of Bitcoin, for me (and I suspect for many), is that you don't have to ask anybody for
permission. If you want to use Bitcoin, you just use Bitcoin. And there isn't anyone who can stop you.</p>
<p><h3>Why not run a full node?</h3></p>
<p>Running a full node is the "correct" thing to do.</p>
<p>But I've tried to run a full node before and always been plagued by crashes and corruptions long before it had finished
syncing. The network relies on full nodes - without full nodes there is no network - but for me the cost of
running a working full node is just too high, so for now I find it easier to work without one.</p>
<p><h3>How to do it</h3></p>
<p>You will most likely need some prior experience of at least <i>using</i> Bitcoin.
You will also need to do some programming to automate the process.</p>
<p><h3>Generate addresses and private keys</h3></p>
<p>I use the <tt>keyconv</tt> program from <tt><a href="https://github.com/samr7/vanitygen">vanitygen</a></tt> as  a
convenient way to do this. Simply running "<tt>keyconv -G</tt>" generates an address and private key and
outputs them.</p>
<p><small>(If you're using a RHEL-based system then you may find that <tt>vanitygen</tt> and <tt>keyconv</tt> segfault
instead of doing anything useful. This is because the packaged version of OpenSSL is crippled due to "patent concerns" and does not
contain the <tt>secp256k1</tt> elliptic curve. The path of least resistance around this is to compile OpenSSL yourself
and link <tt>keyconv</tt> against your own version.)</small></p>
<p><h3>Associate addresses with users</h3></p>
<p>Reusing addresses has security and privacy implications
(<a href="https://en.bitcoin.it/wiki/Address_reuse">read more here</a>), so you want to generate
a fresh address for the user after every payment you receive, but you still want to accept payments
to old addresses in case the user reuses them. So make sure you can handle multiple addresses
per user.</p>
<p>You would ideally have a page showing the user the payments they've made, including
unconfirmed ones, with a link to the transaction on blockchain.info or equivalent. This isn't strictly
necessary, but it is nice for users, and gives them confidence in your ability to correctly process
their payments.</p>
<p><h3>Check for incoming payments</h3></p>
<p>This is the tricky part. The best solution is to run a full node so that you have a local, indexed copy of the
blockchain that you can query at will. The solution I use is to check for payments in a 1-minute cron job using <tt>electrum</tt>.</p>
<p>My first idea was to check for payments by iterating over the list of addresses and calling "<tt>electrum getaddresshistory <b>$address</b></tt>", but
this becomes too slow to be practical after about 50 addresses.</p>
<p>A better option is to create a watch-only wallet, watching the payment addresses, and then query the wallet for its history. You create a
watch-only wallet with "<tt>electrum restore "addresses..."</tt>" - i.e. pass a list of Bitcoin addresses to "<tt>electrum restore</tt>".</p>
<p>The output of "<tt>electrum history</tt>" is some JSON describing the history of transactions for the wallet. For any new transaction
ids, you can call "<tt>electrum gettransaction <b>$txid</b></tt>" to get the serialised form of the transaction, and then
"<tt>electrum deserialize <b>$txn</b></tt>" to learn the value and outputs of the transaction.</p>
<p>Example with only one address (134BLMLjWNDhEQHxKV2pv6Z2Cq8UdSN2d9):</p>
<p><pre style="height: 300px; resize: both"><code>$ electrum -w tmpwallet.dat restore <b>134BLMLjWNDhEQHxKV2pv6Z2Cq8UdSN2d9</b>
Recovering wallet...
Recovery successful
Wallet saved in '/home/jes/tmpwallet.dat'</p>
<p>$ electrum -w tmpwallet.dat history
[
    {
        "confirmations": <b>2982</b>, 
        "date": "2016-10-22 12:34", 
        "label": "", 
        "timestamp": 1477136093, 
        "txid": "<b>18e3535ef545a1bdf8e689edbe913fe69049147e75ebad01f657185ac5766b7e</b>", 
        "value": 0.2
    }
]</p>
<p>$ electrum gettransaction <b>18e3535ef545a1bdf8e689edbe913fe69049147e75ebad01f657185ac5766b7e</b>
{
    "complete": true, 
    "hex": "<b>01000000011702f547056eb8da406592ebcb363f5287dfdad41e0b64d0d29a5e5d038cc46a000000006a47304402202e408edea5c44dca5da17cddd70be3967cd42cde80ab8032011b0055c8a6125d022052a0316c6cf818d893afe9c6a4110b0ae67756b04afa4acc52acc52204cd8b65012103f3afd6ee54dbfe17676374850834afc33ee211ed360eb770583da1a9ba0595edffffffff0254991c00000000001976a91423782fb9e89233cc4bb940fd5de0c7650629020a88ac002d3101000000001976a914168a202310a4c3ada521c07a9ea3caa828fe1d0188ac00000000</b>"
}</p>
<p>$ electrum deserialize <b>01000000011702f547056eb8da406592ebcb363f5287dfdad41e0b64d0d29a5e5d038cc46a000000006a47304402202e408edea5c44dca5da17cddd70be3967cd42cde80ab8032011b0055c8a6125d022052a0316c6cf818d893afe9c6a4110b0ae67756b04afa4acc52acc52204cd8b65012103f3afd6ee54dbfe17676374850834afc33ee211ed360eb770583da1a9ba0595edffffffff0254991c00000000001976a91423782fb9e89233cc4bb940fd5de0c7650629020a88ac002d3101000000001976a914168a202310a4c3ada521c07a9ea3caa828fe1d0188ac00000000</b>
{
    "inputs": [ <i>...snip...</i> ],
    "lockTime": 0, 
    "outputs": [
        <i>...snip...</i>,
        {
            "address": "<b>134BLMLjWNDhEQHxKV2pv6Z2Cq8UdSN2d9</b>", 
            "prevout_n": 1, 
            "scriptPubKey": "76a914168a202310a4c3ada521c07a9ea3caa828fe1d0188ac", 
            "type": 0, 
            "value": <b>20000000</b>
        }
    ], 
    "version": 1
}</code></pre></p>
<p>By parsing this JSON we can learn the value (which is given in
<a href="https://en.bitcoin.it/wiki/Units">satoshis</a> in the output of <tt>electrum
gettransaction</tt>; the example shown is 0.2 BTC) transferred to our addresses, and the number of confirmations. Unconfirmed
transactions show up with <tt>confirmations: 0</tt>.</p>
<p>Although unlikely to happen, it is possible for one transaction to pay multiple user accounts on your service, and you
should make sure you handle this appropriately (e.g. make sure you don't assume txids map to payments 1-1).</p>
<p>And in case it's not obvious: make sure you ignore transactions that spend from your users' addresses - this happens
when you sweep the balance into your wallet.</p>
<p>
<h3>Conclusion</h3></p>
<p>To spend your money, just periodically sweep all of your payments into your own wallet so that you can spend the money conveniently. The Electrum
user interface has a tool to sweep private keys: just paste a list of private keys in there and it will sweep them to your
wallet.</p>
<p>And on security: anybody who compromises your server can simply modify your web app to display their own payment addresses to users,
regardless of what security measures you put in place surrounding the generation/storage of the Bitcoin keys. If your server
gets compromised, you can probably assume that any subsequent payments can be stolen. But that doesn't mean previous payments
need to be vulnerable. I use RSA, with only the public key present on the server, to encrypt the Bitcoin keys before writing
them to disk. When I sweep the payments, I decrypt using the private key which is kept in my "cold storage" (i.e. on a USB stick).
This means there are no Bitcoin keys available on the server, so previous payments can't be taken. </p>
<p>Accepting Bitcoin payments without relying on a payments service is feasible for any sufficiently-motivated developer. Running a full node
is preferable where possible, but if you can't run a full node, you're not automatically SOL.</p>
<p>If you can see any security (or other) flaws in my system, or have any ideas for improvements, or just want to talk
about Bitcoin, please email
<a href="mailto:james@incoherency.co.uk">james@incoherency.co.uk</a>. Thanks for reading.</p>
<p><b>Update 2016-11-12:</b> A couple of people mentioned using HD wallets: I initially tried using an HD wallet, but the mechanism for interacting with it was more inconvenient than generating keys manually - especially considering that you might have to generate hundreds of addresses in a row that never receive a payment. If you find it easier to run it using an HD wallet, then that's a perfectly good alternative.</p>
<p><b>Update 2017-03-06:</b> The method of using Electrum watch-only wallets ceases to be practical after ~1000 addresses. If your service is successful
enough that you have to watch over 1000 addresses, you can probably afford to run a full node. That's what I do now, at any rate.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/how-to-accept-bitcoin-payments.html</link>
   <guid>http://incoherency.co.uk/blog/stories/how-to-accept-bitcoin-payments.html</guid>
   <pubDate>Fri, 11 Nov 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Bitcoin debit cards: Xapo vs Cryptopay</title>
   <description><![CDATA[I've written before about my Cryptopay Bitcoin debit card.
A number of people on reddit
recommended some other company's offerings that hadn't come up in my searches. Xapo was most recommended, so I bought a Xapo card shortly after and
have been using it on-and-off ever since.]]></description>
   <content:encoded><![CDATA[<p>I've written before about my <a href="https://incoherency.co.uk/blog/stories/bitcoin-debit-card.html">Cryptopay Bitcoin debit card</a>.
A number of people <a href="https://www.reddit.com/r/Bitcoin/comments/4vbnzi/living_with_a_bitcoin_debit_card/">on reddit</a>
recommended some other company's offerings that hadn't come up in my searches. Xapo was most recommended, so I bought a Xapo card shortly after and
have been using it on-and-off ever since.</p>
<p>I earn Bitcoin through <a href="https://smsprivacy.org/">SMS Privacy, my anonymous bitcoin phone number service</a> and
through running a high-frequency trading algorithm across various Bitcoin exchanges (which I intend to write about,
but only after it stops being profitable).</p>
<p><h4>Pricing</h4></p>
<p>The Xapo card turns out to be cheaper than the Cryptopay card in every way. The card is &pound;13 from Xapo, compared to
&pound;15 from Cryptopay. The card costs &pound;7/year from Xapo, compared to &pound;1/mo from Cryptopay. There is a 1%
card loading fee at Cryptopay, and none at Xapo. And looking just now, Cryptopay's buy price (i.e. the amount of pounds
you get to spend per BTC) was a full 1.1% lower than Xapo's, and that's before the Cryptopay card loading fee takes another 1%.</p>
<p><h4>The card</h4></p>
<p>The first thing that struck me about the Xapo card ordering process was that they displayed a picture of what the card
would look like. This excited me as it was a cool-looking black card, and is a large part of what made me place the order.
Unfortunately, when the card arrived, it was a generic-looking grey one. In fact, it looked completely identical to the
Cryptopay card, even down to being issued by the same company (WaveCrest Holdings).</p>
<p><h4>The card debacle</h4></p>
<p>I emailed Xapo support to complain. "Hillary" informed me that they would be coming out with a branded card in a few weeks. So I
waited for the new card, which Hillary agreed to send me free of charge.
When the new card arrived, I was surprised to discover that it too was a generic-looking grey card. This process repeated multiple times. At one point I had
received 3 identical grey cards from Xapo.
Hillary and I developed some rapport during this time; she seemed even more frustrated than I was.</p>
<p>My theory is that WaveCrest Holdings automatically reuse the old card design
when re-issuing a card, so as not to confuse the customer.</p>
<p>Anyway, Hillary eventually managed to ship me a cool-looking black card! It doesn't actually have "Xapo" written on it (probably
some regulation prevents that as they are not actually the card issuer), but it is
clearly Xapo's branding, and looks a lot cooler than the grey ones.</p>
<p><img width="300px" src="https://img.incoherency.co.uk/1334"><br><small><i>It actually looks like this</i></small></p>
<p><h4>Their website</h4></p>
<p>In spite of using fancy new web 3.0 Javascript technologies (or perhaps <i>because of</i>?), I consider Xapo's website to
be worse than Cryptopay's:</p>
<p><b>The login process</b> uses a PIN instead of a password. I don't know why. And even if
(like me) you consider your mobile phone to be a borderline-untrusted device, there is no way to disable 2 factor
authentication. So instead of allowing users to choose strong passwords, Xapo require users to place their security
in the hands of a 4-digit number and an insecure device that they carry around everywhere.</p>
<p>Cryptopay <i>support</i> 2 factor authentication, but do not <i>require</i> it. And they allow strong passwords.</p>
<p><b>If you refresh the page</b> on Xapo, you are immediately logged out and must jump through the "go to your phone,
load up 2FA, type in this number" hoops to get back in. I think this is something to do with the
fancy new web 3.0 Javascript technologies.</p>
<p>On Cryptopay, if you refresh a page, it refreshes the contents of the page.</p>
<p><h4>Handling Bitcoin</h4></p>
<p>Cryptopay use a "flex wallet" system, where you have a BTC wallet, a GBP wallet, and then also a GBP balance on the card. To
get Bitcoin on to the card you have to first send the Bitcoin to one of the flex wallets.
Once the payment is confirmed, you can then move the funds to
the card. This means you can't just send some Bitcoin and leave it at that: you have to send the money, wait for
the payment to confirm, and then log back in and move the funds to the card.</p>
<p>With Xapo there is only one balance, and it is always in BTC. This is converted to GBP only when you spend
money on the card. I think this is a much better system.</p>
<p><h4>Overall</h4></p>
<p>In my opinion, the Xapo offering is better than the Cryptopay offering in every way apart from the website. Fortunately,
everyday use of the card does not involve use of the website so this is not too big a deal. However, friction in the login
process has prevented me from depositing funds at least once.</p>
<p>I will probably switch to using the Xapo card exclusively.</p>
<p><small>Neither Xapo nor Cryptopay have compensated me for writing about them. All opinions are my own.</small>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/xapo-vs-cryptopay.html</link>
   <guid>http://incoherency.co.uk/blog/stories/xapo-vs-cryptopay.html</guid>
   <pubDate>Mon, 31 Oct 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made a hidden bookcase door</title>
   <description><![CDATA[Ever since Emma and I moved into this house, I've been talking about making a hidden
bookcase door. Well I've done it now.]]></description>
   <content:encoded><![CDATA[<p>Ever since Emma and I moved into this house, I've been talking about making a hidden
bookcase door. Well I've done it now.</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/EpDn1dCCChE" frameborder="0" allowfullscreen></iframe></p>
<p>There's a closet in the corner of my office which rarely gets used, and seemed like the best choice
for a bookcase door. I began by removing the existing door and pulling off the trim. This was surprisingly
enjoyable, though I made a bit of a mess of the wall, with chunks of plaster falling off.</p>
<p><img width="400" src="https://img.incoherency.co.uk/1313"></p>
<p>I made the surrounding frame of the bookcase, and added a temporary brace, while I worked on the hinge design.
The frame is held together with glue and screws. I sized the frame quite conservatively to make sure I had room
for the hinges. It could have been a bit bigger but worked out OK in the end.</p>
<p><img width="400" src="https://img.incoherency.co.uk/1314"></p>
<p>At the top and bottom of the bookcase there is a 12mm bolt and some plywood spacers. The bottom hinge (as it holds
the most weight) also has a steel spacer hammered into the bookcase part, and a steel washer in between, so that all
of the "bearing" surface is metal.</p>
<p><img width="400" src="https://img.incoherency.co.uk/1315"></p>
<p>With the hinges in place I added shelves and backs to the bookcase, and I added some trim pieces to the top and right
edges that would reduce the gaps later on.</p>
<p><img width="400" src="https://img.incoherency.co.uk/1317"></p>
<p>I then added some outer trim pieces, and the door was starting to look hidden. The top and right trim are attached to the wall. The left trim is attached
to the bookcase, and opens with the door.</p>
<p><img width="400" src="https://img.incoherency.co.uk/1330"></p>
<p>The gap when the door is open is large enough to use but smaller than it is with a normal door.</p>
<p><img width="400" src="https://img.incoherency.co.uk/1331"></p>
<p>I polyfilled the chunks I had lost out of the wall, and gave the bookcase a few coats of paint. The B&Q Colours own-brand "one-coat"
"high-sheen" gloss is neither of those, do not buy it, I was thoroughly disappointed with it. Dulux worked a treat and was only marginally more expensive.</p>
<p><img width="400" src="https://img.incoherency.co.uk/1332"></p>
<p>I also fitted a latch operated by the top-right-most book (demonstrated in the video).</p>
<p>I'm pretty pleased with the bookcase, I did a better job than I expected.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/hidden-bookcase-door.html</link>
   <guid>http://incoherency.co.uk/blog/stories/hidden-bookcase-door.html</guid>
   <pubDate>Fri, 21 Oct 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>SMS Privacy month 1 review</title>
   <description><![CDATA[It's a month since I launched SMS Privacy, a web service
offering anonymous phone numbers paid in Bitcoin. This is what's happened
over the last month...]]></description>
   <content:encoded><![CDATA[<p>It's a month since I launched <a href="https://smsprivacy.org/">SMS Privacy</a>, a web service
offering anonymous phone numbers paid in Bitcoin. This is what's happened
over the last month...</p>
<p><b>172</b> users signed up, paying a total of <b>0.52 BTC</b> (~&pound;260).</p>
<p>At launch the site only supported SMS and only provided "virtual" numbers. A major use case for an
anonymous phone number is to receive signup verification codes, and
unfortunately the API provider blocks such messages. So shortly after launch, I added
<a href="https://incoherency.co.uk/blog/stories/sms-privacy-voicemail.html">voicemail support</a>, which allows it to work for services
that can read the number as a voice call.</p>
<p>For services that do not provide the verification code over a voice call, I now offer "premium" or "physical"
numbers (the A/B test to decide on a name is still inconclusive). The premium/physical service is where I have real SIM cards in real phones, running an Android app that forwards all the
received SMS to the SMS Privacy server. It's like my own mini-Twilio service, but with no message filtering.</p>
<p>When a phone needs a new number (i.e. the user it was assigned to stopped paying for it) it vibrates every 5 minutes, and when I notice it vibrating I put a new SIM card in it.
The phone then announces its number to the SMS Privacy server and the new number is made available for sale.
So far there is only one phone, but I've got another on its way and I plan to add more until I can meet the
demand.</p>
<p><img src="https://img.incoherency.co.uk/1323"></p>
<p>I added an A/B testing framework shortly after launching, and one of the most surprising outcomes
was that replacing the picture of a spy (?) with a picture of Kim Jong-Un increased signups by <b>50%</b> (statistically
significant, p < 0.05). I have no explanation for that. I only chose the picture of Kim Jong-Un because it
was a convenient black-and-white clipart to experiment with.</p>
<p>A few users have emailed to request alternative payment methods, but none of them have suggested the same alternative,
so it's unlikely I'll be adding any soon.</p>
<p>My biggest difficulty (as ever) is marketing. I now have a good service that can take users in and get profit out, I just need
a way to get more users in, and then I can apply that repeatedly to get more profit out. This is
something I plan to improve over the next few months.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/sms-privacy-1-month.html</link>
   <guid>http://incoherency.co.uk/blog/stories/sms-privacy-1-month.html</guid>
   <pubDate>Mon, 10 Oct 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>SMS Privacy now provides anonymous voicemail</title>
   <description><![CDATA[One of the use cases that inspired me to create SMS Privacy is signing up for
accounts for online services without having to link that to a real-world identity. Unfortunately,
it turned out that my API provider is blocking the verification codes that many of
these services send, in an effort to prevent people from abusing their API to automate
the bulk creation of accounts.]]></description>
   <content:encoded><![CDATA[<p>One of the use cases that inspired me to create SMS Privacy is signing up for
accounts for online services without having to link that to a real-world identity. Unfortunately,
it turned out that my API provider is blocking the verification codes that many of
these services send, in an effort to prevent people from abusing their API to automate
the bulk creation of accounts.</p>
<p>Today I added voicemail support to <a href="https://smsprivacy.org/">SMS Privacy</a>.
It now dynamically gives the API provider a <a href="https://en.wikipedia.org/wiki/VoiceXML">VoiceXML</a> document that says "Leave a message" and then records
everything the caller says after that, up to a maximum of 5 minutes. After the caller
has hung up, or the 5 minutes are up, an mp3 recording is uploaded to the SMS Privacy
server, which is made available in the user interface using the HTML5 audio tag.</p>
<p>This is great for interacting with people who don't know you can only send SMS: if they
attempt to call the number, they can now leave a message rather than being unable to
get through.</p>
<p>This is also great for signing up to some online services anonymously. While the API provider
blocks some of the SMS verification codes, the voice calls still get through, so
it now works for signing up to services that can send verification codes over a voice
call.</p>
<p>This is good.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/sms-privacy-voicemail.html</link>
   <guid>http://incoherency.co.uk/blog/stories/sms-privacy-voicemail.html</guid>
   <pubDate>Mon, 19 Sep 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>What is the most interesting thing live streaming right now?</title>
   <description><![CDATA[I had an idea for an interesting project: it would simply show whatever is the most interesting
live stream available at the current moment. It ought to update the stream dynamically whenever
a new more interesting stream becomes available.]]></description>
   <content:encoded><![CDATA[<p>I had an idea for an interesting project: it would simply show whatever is the most interesting
live stream available at the current moment. It ought to update the stream dynamically whenever
a new more interesting stream becomes available.</p>
<p>By way of an MVP, I wrote a program to scrape <a href="https://www.youtube.com/channel/UC4R8DWoMoI7CAwX8_LjQHig/featured">https://www.youtube.com/channel/UC4R8DWoMoI7CAwX8_LjQHig/featured</a>, which lists a bunch of live streams on YouTube. The script then chooses the stream
that has the most viewers, and updates an index.html file to embed that stream. You can watch it at <a href="http://stream.jes.xxx/">stream.jes.xxx</a> (it probably
won't work on mobile).
The page does not currently update to a new stream if a new one takes over (update 2016-09-18: it does now), maybe I'll sort that out in the future. Just manually refresh the page whenever you
want to check for a new stream. There's a lot of scope to improve on this MVP.</p>
<p>So far today we've had about 8 hours of oily men (apparently the <a href="http://mrolympia.com/">"Mr. Olympia 2016"</a> ceremony was really really popular) followed
by a football match between Etoile de Sahel and Mazembe, with Arabic commentary. The match ended in a 1-1 draw. This was followed by
some live action of a guy with a goatee playing Minecraft, for about 5 minutes, followed by a guy <i>without</i> a goatee playing Grand Theft Auto.</p>
<p><a href="https://www.facebook.com/live">Facebook Live</a> is similar to this idea. Facebook Live contains more individuals' streams and less
"organised" streaming. I think it would be great to incorporate Facebook Live streams when they are more popular than
the YouTube ones. For example, it could switch to a stream showing the aftermath of
<a href="https://en.wikipedia.org/wiki/Shooting_of_Philando_Castile">the shooting of Philando Castile</a>,
at the moment it becomes more popular than the oily men parade.</p>
<p>A handful of people have proposed ideas along the lines of selecting a stream based on the user's personal preferences. But I think the main appeal of
this project is that you're not viewing the world through the lens of your filter bubble, you're just watching
whatever is going on, live, that the most other people are interested in watching.</p>
<p>Using popularity as a heuristic for "interesting" is far from perfect, but probably good enough for now. Maybe a better metric
would involve some measure of the rate of growth of the number of viewers.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/streaming.html</link>
   <guid>http://incoherency.co.uk/blog/stories/streaming.html</guid>
   <pubDate>Sat, 17 Sep 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The SMS Privacy conversion funnel</title>
   <description><![CDATA[I'm a big fan of Patrick McKenzie's blog.
If you're interested in small-time software business it's worth working through
his greatest hits page. A powerful
idea I learnt from his site is the conversion funnel: all the visitors to your site pour into
the top, they then pass through several filter layers, and some proportion of them pop out at the bottom as paying customers. To
get more paying customers you either need to put more users in the top, or get a higher proportion of
them to pop out at the bottom.]]></description>
   <content:encoded><![CDATA[<p>I'm a big fan of <a href="http://www.kalzumeus.com/blog/">Patrick McKenzie's blog</a>.
If you're interested in small-time software business it's worth working through
his <a href="http://www.kalzumeus.com/greatest-hits/">greatest hits page</a>. A powerful
idea I learnt from his site is the <a href="https://en.wikipedia.org/wiki/Conversion_funnel">conversion funnel</a>: all the visitors to your site pour into
the top, they then pass through several filter layers, and some proportion of them pop out at the bottom as paying customers. To
get more paying customers you either need to put more users in the top, or get a higher proportion of
them to pop out at the bottom.</p>
<p>In the 3 days it's been operational, the <a href="https://smsprivacy.org/">SMS Privacy</a> home page has been viewed 5,000 times. I'm happy with that,
as the sum total of my marketing efforts consist of an unsuccessful Hacker News post and 2 reddit posts.</p>
<p>This gave an opportunity to analyse the conversion funnel to see where improvements can be made.</p>
<p><b>5%</b> of users who viewed the home page went on to view the signup page. I think this is fine. Anecdotally, I probably don't view
the signup page of 5% of the websites I look at, so it's probably better than average.</p>
<p>Of the users who viewed the signup page, <b>30%</b> went on to sign up (aside: I was pleasantly surprised to find that a full 10% of the users
had signed up using the Tor hidden service!). Ordinarily this might be pretty good. It's certainly better than
any of my previous projects. But given that the signup page only has 2 fields I'd think a majority ought to be persuaded to fill them in.</p>
<p><img style="padding: 20px" src="https://img.incoherency.co.uk/1309"></p>
<p>To make the page a bit more compelling I changed the boring paragraph of smallprint, and also made the username field autofocus. (I know, I know. I should
be running independent A/B tests to determine the impact of each change independently. Still better than nothing.)</p>
<p>Of the users who signed up, <b>75%</b> went on to view the "deposit funds" page. Very happy with this. On the first login the user is immediately greeted with
"Woohoo! You're in. You'll need to deposit some funds", which seems to be working well.</p>
<p>Of the users who viewed the "deposit funds" page, <b>35%</b> deposited some funds. The step where users have to part with some hard-earned cash
is always going to have fairly high attrition, so I think 35% here is okay, though it's probably the next thing to optimise.</p>
<p>With any luck the sign up page conversion rate will improve over the next few days.</p>
<p><b>Update 2016-09-16:</b> over the last 4 days, <b>42%</b> of users who viewed the signup page went on to sign up, up from 30%. Excellent.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/sms-privacy-funnel.html</link>
   <guid>http://incoherency.co.uk/blog/stories/sms-privacy-funnel.html</guid>
   <pubDate>Mon, 12 Sep 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to buy phone numbers anonymously</title>
   <description><![CDATA[Over the last week or so I've been working on a project that allows anyone to
buy phone numbers using Bitcoin anonymously, and use them to send and receive
SMS. I think this is an important piece of the puzzle of allowing people to
interact with the world anonymously, as a large number of services use
SMS for account verification or 2-factor-authentication.
Being able to buy phone numbers anonymously allows you to create new identities
more easily.]]></description>
   <content:encoded><![CDATA[<p>Over the last week or so I've been working on a project that allows anyone to
<a href="https://smsprivacy.org/">buy phone numbers using Bitcoin anonymously</a>, and use them to send and receive
SMS. I think this is an important piece of the puzzle of allowing people to
interact with the world anonymously, as a large number of services use
SMS for account verification or 2-factor-authentication.
Being able to buy phone numbers anonymously allows you to create new identities
more easily.</p>
<p>(Update: now available as a Tor hidden service at <a href="http://smspriv6fynj23u6.onion/">smspriv6fynj23u6.onion</a>)</p>
<p>I launched SMS Privacy yesterday by posting it to Hacker News and the r/bitcoin
subreddit. Few people on HN were interested.
It took off more on r/bitcoin, however, reaching the number 3 spot at one point.</p>
<p>The upshot of this is that there are now 48 SMS Privacy user accounts, 20 messages have
been sent/received, and 10 numbers have been bought. This is the most successful project launch I've had yet.
Most importantly, real people have sent me real money, to the tune of 0.12 BTC (~&pound;57).</p>
<p>There
is definitely more marketing work to do, as usage of the site has dropped off now that it's off the
front page of r/bitcoin, but hopefully it'll have a couple of regular users and will continue to grow.</p>
<p>I think this demonstrates that there is a market for "normal" services that allow anonymous signup.
For anybody so inclined, I think a good market to enter would be anonymous VPS hosting: <a href="https://www.orangewebsite.com/">orangewebsite</a>
already provide this, but it is extremely expensive (&euro;30/mo for a VPS with only 512M of RAM). I think it shouldn't be too hard to undercut them.</p>
<p>Finally, a couple of people expressed concern that SMS Privacy might primarily be used by fraudsters.
I was ignoring this issue to start with, on the basis that "we don't like the users" is a better
problem than "there are no users". I don't think this is a huge problem, however, as
the service doesn't allow you to do anything you couldn't already do by walking into a shop
and buying a phone and SIM card with cash. Another analogy is that I'm just the SMS equivalent of
a Tor exit node. Still, I'd rather SMS Privacy not be used by frausters, so I welcome
suggestions that might disincentivise fraud without deanonymising users.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/sms-privacy.html</link>
   <guid>http://incoherency.co.uk/blog/stories/sms-privacy.html</guid>
   <pubDate>Sat, 10 Sep 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>What if we could assume new identities at will?</title>
   <description><![CDATA[I've been thinking a lot about privacy and anonymity recently. It's reasonably
possible to create a new online identity, with no links to your real-world
identity, as long as you don't need to buy anything and you're careful. Use Tor,
get an email address from SIGAINT, and you can
sign up for accounts on a lot of other services and speak your mind freely.]]></description>
   <content:encoded><![CDATA[<p>I've been thinking a lot about privacy and anonymity recently. It's reasonably
possible to create a new online identity, with no links to your real-world
identity, as long as you don't need to buy anything and you're careful. Use <a href="https://torproject.org/">Tor</a>,
get an email address from <a href="https://sigaint.org/">SIGAINT</a>, and you can
sign up for accounts on a lot of other services and speak your mind freely.</p>
<p>New identities created in this manner come with a few limitations:</p>
<p><h4>Purchases</h4></p>
<p>It is almost impossible to purchase anything online both anonymously and legally. Cash only works
offline. Stealing credit
card numbers allows you to be anonymous but is illegal, and rather distasteful (you're stealing
from real people). Any other conventional payment method that works online is not at all anonymous
(PayPal, bank transfers, spending from your own credit card). And furthermore, thanks to anti-money
laundering regulations, I don't think any anonymous payment method can be created unless there is
nobody to prosecute.</p>
<p>Bitcoin improves the situation here: if you can acquire the
BTC anonymously (e.g. by selling your services on a dark market) then you can safely spend it
without any link to your real-world identity. But thanks to the public ledger, transferring value from your real-world identity
to your new identity without any traces is very difficult and probably still leaks <i>some</i> information
even if a concrete connection can't be drawn.</p>
<p><a href="https://en.wikipedia.org/wiki/Monero_(cryptocurrency)">Monero</a> purports to solve the anonymous
payments problem, but I've not looked in any detail.</p>
<p><h4>Deliveries</h4></p>
<p>Even if you can solve the purchasing problem, naive delivery of physical goods would reveal your physical location.</p>
<p>If you could anonymously acquire a PO Box or similar, this would still leak a lot of information about
your location (e.g. it's impractical to use a PO Box in Canada if you live in England).</p>
<p>Maybe a concept like Tor could be made to work?
The packages would have to be well-secured to ensure that the middlemen can't reasonably open them, both to protect
the content of the package from inspection/modification, and to protect the middlemen from liability.</p>
<p>There would 
need to be a disincentive against theft.
The cost paid to each middleman would need to be higher than the net profit he could make
by stealing the package. Either his delivery fee must be expensive, or the package must
be expensive to open. Either way, it's going to be expensive.</p>
<p>As presented here, this idea is unworkable, but if you have any insights into how it could work, please get in touch.</p>
<p><h4>Slip-ups</h4></p>
<p>As an experiment, I recently tried to rent a VPS anonymously. I habitually signed off a support ticket with
"Thank you. James" and sent it before realising my mistake. This isn't enough to uniquely identify me, but it opened my eyes
to how easy it is to slip up. And each mistake reduces the set of real-world people who
could be behind the identity.</p>
<p><h4>Legal system</h4></p>
<p>As part of the anonymous VPS experiment, I requested a refund of my 0.06 BTC. I still haven't received it. If the people running
the hosting company can be sure enough that I signed up using "false" information, they can quite easily get
away with not sending the refund. What am I going to do? A "false" identity can't participate in the legal system so my only
recourse is to complain about it.</p>
<p><h4>But this isn't about that</h4></p>
<p>This article isn't about the problems that come with creating new identities. Let's instead assume a society in which we
can use cryptography to create first-class identities whenever we want. Just create another keypair, and that's another
identity. What are the implications of such a society?</p>
<p>To be clear, I'm not talking about identity theft. The current systems make it easier to assume a new identity by stealing
one from somebody else than by creating a fresh one. No, I'm talking about the ability to create completely new identities,
backed entirely by cryptography, not by national registers of births, immigrations, etc.</p>
<p>On this point, the world is currently diverging. On one hand, governments are increasing their control and surveillance
over ordinary people. Technology is allowing them to make connections between different parts of our lives in ways that
weren't possible even 20 years ago. On the other hand, technology like Tor, Bitcoin, and plenty more, are allowing people to assume new <i>online</i>
identities without asking permission from anyone, outside the scope of government
databases. I don't know if this divergence can continue forever, and I don't know how it can be resolved.</p>
<p>In a world where identities are proven by cryptography rather than by passport photos and bank statements, identity theft becomes
a lot more difficult. In the current world, anybody who can verify an identity (for example by receiving a copy of a
passport and bank statement) gets all the info they need in order to steal that identity. If, instead, identities
are backed by cryptography, you just sign a message and never reveal your private key.</p>
<p><h4>What gets worse?</h4></p>
<p>It might make credit scores less effective. Anybody who wants to default on a
loan can do so, easily, without any impact on the credit scores of their other identities.</p>
<p>It might not be possible to conduct elections where each person has exactly one vote. Which identities are allowed a vote and which ones aren't?</p>
<p>Our current system of taxes might not work well. At minimum, tax bands would have to be reconsidered, otherwise people could create
many identities, and keep each one in the lowest band, rather than paying more tax. And, more likely, taxes wouldn't even work: if
I can create a new identity outside any government database, how will the government even know to <i>try</i> to collect taxes from me? And how
can they punish me if I don't pay?</p>
<p>How would driving licences work? If I run over an old lady and have my licence
revoked, what stops me from simply creating a new identity and getting a new driving licence?</p>
<p>Anything based on proof of age would probably have to change (laws around buying alcohol, for instance) because any mechanism that could tie an identity
to a person's age could also be used to tie all of that person's identities together (or, at minimum, would leak information that could be used to help tie
them together).</p>
<p>Some identities could be controlled by groups rather than an individual, without anybody else knowing how many people are behind it. If this
group identity had a driving licence then it would allow all members of the group to drive even though only one of them had actually
passed the test.</p>
<p><h4>Final thoughts</h4></p>
<p>The ideas here are not well-formed, but perhaps the Nash equilibrium is somewhere close to governments requiring you to
tell them about all of your identities so that they can assign voting rights, collect taxes, etc. There could be a punishment for
anybody found to be using an identity that their local government hasn't been informed of, and probably driving licences etc.
would not be granted to identities that are controlled by multiple people. There would probably be some way for companies
not only to verify an identity (use cryptography) but to check with the local government to make sure it is a "legitimate" identity, and possibly even to get a list
of other identities possessed by the same person. Perhaps crypto-anarchy is destined to be forever confined to the virtual world.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/identities.html</link>
   <guid>http://incoherency.co.uk/blog/stories/identities.html</guid>
   <pubDate>Sun, 21 Aug 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Living with a Bitcoin debit card</title>
   <description><![CDATA[My new project produces profit in Bitcoin. I wanted a way to be able to spend the Bitcoin without having to:]]></description>
   <content:encoded><![CDATA[<p>My new project produces profit in Bitcoin. I wanted a way to be able to spend the Bitcoin without having to:</p>
<p>a.) limit my purchases to places that accept Bitcion, or<br>
b.) sell on Localbitcoins and risk the bank freezing my account for accepting money from drug dealers, or<br>
c.) sell on Coinbase and wait 3-5 business days to get the money in my bank account</p>
<p>I shopped around for a Bitcoin debit card and settled on
<a href="https://cryptopay.me/bitcoin-debit-card">Cryptopay's offering</a>. The card costs &pound;15 upfront + &pound;1/mo.
Plus you pay a 1% fee for currency conversion (e.g. converting your Bitcoin to Pounds).
There's also a &pound;1.75 charge for withdrawing cash from an ATM, so I won't be doing that.</p>
<p>You do unfortunately have to send photographs of government-issued identification documents for
<a href="https://en.wikipedia.org/wiki/Know_your_customer">KYC/AML reasons</a>, but it was quite quick and the
support staff were very helpful (I initially filled out the form wrong but Alexey sorted it out for me).</p>
<p>The card arrived sooner than I expected: the website said it could take up to 10 days, but it arrived after 3.</p>
<p>Upon opening the package I was a little surprised to find all of the marketing materials referred to
<a href="https://www.mychoicecorporate.com/en/home/">MyChoiceCorporate</a> and
<a href="https://www.wavecrest.gi/">Wave Crest Holdings</a>. The card is actually issued by one of those companies,
but (other than the automated phone line to get my PIN code) I haven't had to interact with them as the
Cryptopay website does everything.</p>
<p><img width="200px" src="https://img.incoherency.co.uk/1298"><br><small><i>It doesn't look like this</i></small></p>
<p>I was disappointed to find that rather than
a cool-looking black card with "CRYPTOPAY" written on the top (like the example on the Cryptopay website),
it was a generic-looking grey card. I asked Alexey about this and he said they would
love to have Cryptopay written on the card, but Visa do not allow it (I assume because Cryptopay are not
the card issuer). It would still be cooler if it was black.</p>
<p>I've been using the card for the past week and in most cases it's been no different to
using my bank card. The payment authorisations show up on the Cryptopay website immediately, which is a nice touch, compared to
my bank where they only show up a few days later.</p>
<p>The only problem I've had is when I tried to buy a new keyboard off eBay and paid with the Cryptopay card, via PayPal.</p>
<p>Since the card is issued from Gibraltar, it seems PayPal actually took payment in Gibraltar Pounds instead
of British Pounds, so the card issuer charged me &pound;1.72 for the conversion, and PayPal charged a similar
amount as well. I guess PayPal assumed I would have to pay a currency conversion fee, and they may as well take it
for themselves instead of giving it to the card issuer. A bit scummy of them, but I'll know to watch out in future.</p>
<p>Overall I'm very satisfied with the card. If you have some source of Bitcoin that you want to use where Bitcoin is not accepted,
and you can tolerate the KYC/AML rules, I highly recommend getting a Cryptopay card.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/bitcoin-debit-card.html</link>
   <guid>http://incoherency.co.uk/blog/stories/bitcoin-debit-card.html</guid>
   <pubDate>Sat, 30 Jul 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Perl's Digest::SHA::hmac_sha256_base64 is wrong</title>
   <description><![CDATA[I spent nearly 2 hours today struggling to authenticate with an API that uses base64 SHA256 HMAC's, only
to find that the hmac_sha256_base64 implementation appears to be wrong.]]></description>
   <content:encoded><![CDATA[<p>I spent nearly 2 hours today struggling to authenticate with an API that uses base64 SHA256 HMAC's, only
to find that the <tt>hmac_sha256_base64</tt> implementation appears to be wrong.</p>
<p>For example:</p>
<p><pre><code>#!/usr/bin/perl</p>
<p>use strict;
use warnings;</p>
<p>use MIME::Base64 qw(encode_base64);
use Digest::SHA qw(hmac_sha256 hmac_sha256_base64);</p>
<p>my $key = 'foo';
my $data = 'hello world';</p>
<p>print "hmac_sha256_base64:         " . hmac_sha256_base64($data, $key) . "\n";
print "encode_base64(hmac_sha256): " . encode_base64(hmac_sha256($data, $key)) . "\n";</code></pre></p>
<p>The output is:</p>
<p><pre><code>hmac_sha256_base64:         jvVS287gOBboArZDFbSGoJkwJBVkIGt4nprJe1BOzoo
encode_base64(hmac_sha256): jvVS287gOBboArZDFbSGoJkwJBVkIGt4nprJe1BOzoo=<br>
</code></pre></p>
<p>Using <tt>hmac_sha256_base64</tt> is (nearly?) always the wrong thing to do, just use <tt>encode_base64(hmac_sha256())</tt>
instead. Also, note that <tt>encode_base64</tt> leaves a spurious trailing endline which you'll have to remove in anything
more than a toy example.</p>
<p>I wasn't able to find any information about this problem online (until after I knew what the problem was - it is <a href="http://search.cpan.org/%7Emshelor/Digest-SHA-5.85/lib/Digest/SHA.pm#PADDING_OF_BASE64_DIGESTS">documented in the POD if you know what to look for</a>), so I'm posting this in case it
helps someone.</p>
<p>I <a href="https://rt.cpan.org/Ticket/Display.html?id=115918">submitted a bug report</a> before I read the POD, but it will presumably not get fixed.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/hmac-sha256-base64-is-wrong.html</link>
   <guid>http://incoherency.co.uk/blog/stories/hmac-sha256-base64-is-wrong.html</guid>
   <pubDate>Wed, 06 Jul 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>On the design of a herb jar lid</title>
   <description><![CDATA[My herb jar lid has two operating modes:
one has small holes which allow you to shake the herb out slowly, and the other
is a single large hole which allows you to shake the herb out quickly.]]></description>
   <content:encoded><![CDATA[<p>My herb jar lid has two operating modes:
one has small holes which allow you to shake the herb out slowly, and the other
is a single large hole which allows you to shake the herb out quickly.</p>
<p>Observe:</p>
<p><img src="https://img.incoherency.co.uk/1296" width="500"></p>
<p>I am regularly frustrated by this jar because the large hole dumps way too much herb
on my food, and the small holes require me to shake the thing for ages.</p>
<p><h3>Methodology</h3></p>
<p>I set up a little experiment. I emptied the herb
into a bowl and had an assistant time how long it took to empty, then I carefully refilled
the jar and we did it again, until we had enough results.</p>
<p><h3>Results</h3></p>
<p><table border>
<tr><th>Big hole</th><th>Small holes</th></tr>
<tr><td>5.3 s</td><td>560 s</td></tr>
<tr><td>5.4 s</td><td>-</td></tr>
<tr><td>6.1 s</td><td>-</td></tr>
</table></p>
<p>You'll notice I only have one result for the "small holes" test. This is
because it took nearly 10 minutes and my assistant had had enough. And
besides, my arm was tired of shaking.</p>
<p>It takes approximately <b>100 times</b> as long to get the herb out of the small
holes compared to the large holes.</p>
<p><h3>Conclusions</h3></p>
<p>The small holes are way too small. But why is it this way? Does the manufacturer not
test the product before they sell it? I have two theories:</p>
<p>1.) The jar is standardised across a range of different herb and was tested
against a herb (or possibly even a spice) that comes in smaller pieces.</p>
<p>2.) The jar was designed for this herb, but the ingredients have changed over
time (deliberately or not) to favour larger pieces of herb.</p>
<p>I don't know which is more likely. I hope the jar has changed in a few years' time
when I need to buy some more, but I am not holding my breath.</p>
<p><h3>Confounding variables</h3></p>
<p>It is likely
that the repeated shaking of the herb causes it to break down into smaller
pieces and therefore flow slightly faster with each subsequent test.
I don't think this invalidates the experiment.</p>
<p>I failed to control for the shaking technique: I
tried to shake the herb out as fast as I could each time, but my arm certainly
got tired in the "small holes" test. I don't think this
invalidates the experiment.</p>
<p>Each time I emptied the jar, I probably lost a little bit of herb. In fact, I certainly
left a little bit in the bowl after the first time I emptied it. I don't think this
invalidates the experiment.</p>
<p>The herb probably flowed out of the small holes
a bit faster at the start than towards the end, because only large pieces were left
towards the end. I don't think this invalidates the experiment either.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/mixed-herb.html</link>
   <guid>http://incoherency.co.uk/blog/stories/mixed-herb.html</guid>
   <pubDate>Mon, 27 Jun 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I delivered an Oak Mirror to a lady</title>
   <description><![CDATA[My latest business venture is Bristol Oak Mirrors.
The website is crap but the idea is I make oak-framed mirrors and sell them.]]></description>
   <content:encoded><![CDATA[<p>My latest business venture is <a href="https://bristoloakmirrors.co.uk/">Bristol Oak Mirrors</a>.
The website is crap but the idea is I make oak-framed mirrors and sell them.</p>
<p><img src="https://img.incoherency.co.uk/1249" width="300"></p>
<p>I made a batch of 5 to start with.</p>
<p>So far I've sold 2 of them, making this the second-most-profitable business venture I've ever done.</p>
<p>It started when I wanted a frame for a piece of mirror glass we had lying around from an old dressing
table. I made an oak frame for it and it looked sweet:</p>
<p><img src="https://img.incoherency.co.uk/1250" width="300"></p>
<p>So I went to the <a href="http://www.bwrp.org.uk/">Bristol Wood Recycling Project</a> and bought a bunch
more oak. I haggled on the price and amazingly they caved and gave me the wood cheaper than advertised. Result!</p>
<p>I thought I could make 5 mirrors in a day but it ended up taking me 3 days. I think I'll get better
though.</p>
<p>I listed the mirrors on eBay and Gumtree this week, and so far I've posted one off on eBay (the postage
came to &pound;30! What a rip!) and delivered one to a lady in Yate.</p>
<p>Delivering the mirror was awesome. I took a bag of tools, felt like a proper little tradesman.</p>
<p>The lady was replacing a non-oak mirror and so already had
mounting screws on the wall, but they weren't lined up with the tabs on my mirror so I moved the tabs.
Her children laughed at me using the drill. I'm not sure if they enjoyed watching it or were just
mocking my technique.</p>
<p>It was a massive buzz to show one to a customer for the first time, and she really liked it. She said
to let her know if I'm selling any other oak furniture but I told her I only do mirrors.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/oak-mirrors.html</link>
   <guid>http://incoherency.co.uk/blog/stories/oak-mirrors.html</guid>
   <pubDate>Fri, 27 May 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to copy Wordpress theme customisations to a child theme</title>
   <description><![CDATA[I've been working with Wordpress a little lately. I learnt that you're supposed to create
a child theme in order to make modifications to it, but I'd already modified the theme
settings (colours, etc.) using the Wordpress 'Customise' tool and couldn't see how to copy
these settings to the child theme.]]></description>
   <content:encoded><![CDATA[<p>I've been working with Wordpress a little lately. I learnt that you're supposed to create
a child theme in order to make modifications to it, but I'd already modified the theme
settings (colours, etc.) using the Wordpress 'Customise' tool and couldn't see how to copy
these settings to the child theme.</p>
<p>I tried to Google for how to do this, but the best I found was:</p>
<p><blockquote>You <i>could</i> migrate those settings, but doing so involves direct manipulation of your SQL database.</blockquote></p>
<p>I thought "yes, I know that, tell me how to do it". So this is that.</p>
<p>There is a row in the <tt>wp_options</tt> table with <tt>option_name='theme_mods_<b>themename</b>'</tt>, for a theme called <tt><b>themename</b></tt>.
All we need to do is copy this row, with <tt>option_name='theme_mods_<b>themename-child</b>'</tt> for our child theme called <tt><b>themename-child</b></tt>.</p>
<p>Run this at the MySQL prompt (edit <tt><b>themename</b></tt> and <tt><b>themename-child</b></tt> appropriately, of course):</p>
<p><pre><code>INSERT INTO wp_options (option_name, option_value, autoload) SELECT 'theme_mods_<b>themename-child</b>', option_value, autoload FROM wp_options WHERE option_name='theme_mods_<b>themename</b>';</code></pre></p>
<p>Then do a 'Live preview' to make sure it worked.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/copy-wordpress-theme-customisation-to-child-theme.html</link>
   <guid>http://incoherency.co.uk/blog/stories/copy-wordpress-theme-customisation-to-child-theme.html</guid>
   <pubDate>Mon, 23 May 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to defeat naive image steganography</title>
   <description><![CDATA[As a teenager, I wrote a C program to do image steganography.
It hid the secret image in the least significant bits of the cover
image. I also made a PHP web interface to it, which now sees about 3,000
users per month. So I've made a better version, it gives previews of the
input images, doesn't upload the images to my server (privacy, yo), and is faster.]]></description>
   <content:encoded><![CDATA[<p>As a teenager, I wrote a C program to do image steganography.
It hid the secret image in the least significant bits of the cover
image. I also made a PHP web interface to it, which now sees about 3,000
users per month. So I've made a better version, it gives previews of the
input images, doesn't upload the images to my server (privacy, yo), and is faster.</p>
<p>The new version is implemented in Javascript and runs in the browser.</p>
<p><a href="http://incoherency.co.uk/image-steganography/">You can play with it here.</a></p>
<p>It's not supposed to be useful, just a bit of fun. The kind of steganography this tool does
is easily defeated by basic analysis of the least significant bits, which is what I want to talk
about now.</p>
<p>An arbitrary photograph, encoded in a bitmap format, would have increasingly-random variation as you
move from the most significant bits to the least significant.
But if a black and white image of some text were hidden there, the least significant bit would
instead have large blocks of identical bits (for black sections and white sections), and almost
no variation.</p>
<p>We can take the value of the 1st bit, 2nd
bit, etc. to create 8 pictures of the different "bit planes" in the image. Here is an example
shamelessly taken from the <a href="https://en.wikipedia.org/wiki/Bit_plane">Wikipedia article
on bit planes</a> (this is greyscale, but we can do the same for colour images):</p>
<p><img src="https://img.incoherency.co.uk/1211" width="500"></p>
<p>The lower right panel is the least significant bit and is indeed pretty random-looking.</p>
<p>If we had a black and white message hidden in the least significant bit, it would look like this
(the most significant bit planes are unchanged, so the output image appears the same):</p>
<p><img src="https://img.incoherency.co.uk/1212" width="500"></p>
<p>We can perform edge detection on the bit planes:</p>
<p><img src="https://img.incoherency.co.uk/1215" width="500"></p>
<p>vs.</p>
<p><img src="https://img.incoherency.co.uk/1216" width="500"></p>
<p>If we then sum the pixel values in each bit plane after edge detection, we get a value that roughly
corresponds to how much noise there is. We can see that, in general, each bit plane has more noise
than the one that came before it, except when there is a steganographically-hidden image.</p>
<p>This reveals a simple algorithm for detecting steganography:</p>
<p>1.) Split the image into its 8 bit planes</p>
<p>2.) Perform edge detection on each bit plane to get edge detection output</p>
<p>3.) Sum the pixels of each edge detection output to get a quantifier for the amount of noise</p>
<p>4.) Starting at the most significant bit and working down: if any plane has less noise than
the one that came before it, this is a good candidate for being a steganographically-hidden image.</p>
<p>It is also relatively easy to see that if a photograph (rather than a block of text) were hidden in the same manner, this algorithm
still has a good chance of working. Here are the bit planes for a Walrus hidden in Lena:</p>
<p><img src="https://img.incoherency.co.uk/1219" width="500"></p>
<p>And after edge detection:</p>
<p><img src="https://img.incoherency.co.uk/1220" width="500"></p>
<p>The first bit plane of the walrus is much less noisy than the last bit plane of Lena.</p>
<p>If you want to play with my steganography tool, <a href="http://incoherency.co.uk/image-steganography/">here is the link again</a>.</p>
<p>If you want to talk about steganography, please get in touch: <a href="mailto:james@incoherency.co.uk">james@incoherency.co.uk</a>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/image-steganography.html</link>
   <guid>http://incoherency.co.uk/blog/stories/image-steganography.html</guid>
   <pubDate>Wed, 27 Apr 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Stockfighter Review (no spoilers)</title>
   <description><![CDATA[I've been playing Stockfighter this week.]]></description>
   <content:encoded><![CDATA[<p>I've been playing <a href="https://www.stockfighter.io/">Stockfighter</a> this week.</p>
<p>The reason I didn't start playing it sooner was my impression that the deal was "do lots of work, and maybe
we'll help you find a new job". But I don't want a new job, so I wasn't interested.</p>
<p>After I read more about it, I decided to give it a try, and it blew me away. The single most
addictive game I've ever played. It has ruined my sleep pattern for the last 3 nights. I would say I wish the
game was longer, but really I'm glad it's over so I don't have to think about it any more. Highly
addictive.</p>
<p>I perhaps had a bit of an advantage over the average player (having written automated bitcoin trading
bots for my Bitgroin hedge fund), but the game presents all of the concepts in a way that should make them
easy to pick up.</p>
<p>I used Perl to do all of the programming, with the excellent <a href="http://mojolicious.org/">Mojolicious</a> providing
the HTTP and websocket client support for the later levels. None of my solutions required a large amount of code,
just a lot of thinking.</p>
<p>I thoroughly enjoyed it, and I recommend everybody go and play it.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/stockfighter-review.html</link>
   <guid>http://incoherency.co.uk/blog/stories/stockfighter-review.html</guid>
   <pubDate>Fri, 22 Apr 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How (and why) to make your software faster</title>
   <description><![CDATA[Have you ever been bothered by how slowly your webapp loads, but never profiled it?
Much like test-driven development and A/B tests, performance profiling almost always throws up surprises and big wins, and
yet most people never bother to do it. If you have anything that
runs too slowly, you should profile it today, you will find improvements to make.]]></description>
   <content:encoded><![CDATA[<p>Have you ever been bothered by how slowly your webapp loads, but never profiled it?
Much like test-driven development and A/B tests, performance profiling almost always throws up surprises and big wins, and
yet most people never bother to do it. If you have anything that
runs too slowly, you should profile it today, you <i>will</i> find improvements to make.</p>
<p><h3>What Profiler Should I Use?</h3></p>
<p>For profiling C, valgrind's <a href="http://valgrind.org/docs/manual/cl-manual.html">callgrind</a> is excellent, and you
can examine the output in <a href="http://kcachegrind.sourceforge.net/html/Home.html">KCacheGrind</a>. For Perl,
<a href="http://search.cpan.org/~timb/Devel-NYTProf-6.03/lib/Devel/NYTProf.pm">NYTProf</a> is excellent, and you can
examine the output in a web browser, using <tt>nytprofhtml</tt>. In the worst case, in any framework, you can insert logging statements
before and after each stage of processing, and find your bottlenecks that way.</p>
<p>A large portion of my day job is speeding up software in various ways: make user interfaces load faster,
make backend processing happen sooner, make backend processing handle more data in parallel. It is almost always
possible to make software faster, and I've noticed some recurring themes. Even in cases where it is not economical
to improve the software itself, you can still make it faster by spending more on hardware. In this age of DigitalOcean droplets
and EC2 instances, this is easier than ever.</p>
<p><h3>The 3 Most Important Things to Know to Make your Software Faster</h3></p>
<p>1.) <b>Profile it</b>. Just having the profiling data gets you 80% of the way there. Get the profiling data, and spend a few minutes looking
at it and deciding whether it makes sense, and which parts seem slower than you expected.</p>
<p>2.) <b>Abstraction layers hide inefficiencies</b>. Layers of abstraction are absolutely necessary for the development of complex
software systems. But often, the abstractions implicitly perform unnecessary work, just because it is sometimes needed. When you spot bottlenecks
in the profiling output, decide whether they absolutely have to exist. It is not unusual for the slow work
to be necessary only in special cases. This is an easy win: run less code.</p>
<p>3.) <b>Database queries</b>. When the software was first written, there wasn't much data, and all was well. Over the years, the database
has grown substantially. Now your profiling shows you that a simple query takes too long. See if you are missing important indexes. If the query is being repeated,
see if you can cache the output, or grab the output for all data items at once instead of repeating the query.</p>
<p><h3>The Business Case</h3></p>
<p>A poorly-performing user interface doesn't just make a task take longer, it discourages you from doing any task that has that
interface as part of the workflow, and provides an opportunity to get distracted. If it's an internal application, it discourages you from doing valuable work. If it's your
product, it discourages your customers from using it. Making the interface faster doesn't just make the task quicker, it enables whole new
classes of tasks that make heavier use of the interface. </p>
<p>A poorly-performing backend process limits your throughput, and thus is a barrier that needs to be knocked down before you can exceed a certain scale.</p>
<p><h3>Case Studies</h3></p>
<p>A process at my day job handles millions of URLs per day. As part of handling each URL, it checked whether the URL was present in the database, and then
logged something if it was. This was implemented so that we could get interesting stats on how many
of the URLs were already present at report time. It turned out that it was spending 30% of its time doing these database queries, there was still no automated
process to generate the stats, and humans had long
since stopped checking. Deleting that 1 line of code knocked 30% off the execution time of every URL.</p>
<p>An admin overview page was spending 2.5ms per item loading extended data. But the page was now an overview of 8000 items, which means it was
spending 20 <b>seconds</b> loading this data. This severely discouraged people from using the interface, and some work went undone. And
it turned out, since the overview page was just an overview, the extended data wasn't even being shown! The abstraction layer
loaded the data implicitly, because it didn't know it wasn't going to be shown. Pass in a flag to make it
stop loading extended data on the overview page: the page loads faster, people use it more,
and more work gets done.</p>
<p><h3>The Hard Sell</h3></p>
<p>Since I <a href="https://incoherency.co.uk/blog/stories/going-solo.html">stopped doing my day job full-time</a>, I am able to take on more projects. Here's my pitch:</p>
<p><b>If I can't make your worst-performing page load 50% faster, you don't have to pay the bill.</b></p>
<p>Get in touch if you think you might want to hire me: <a href="mailto:james@incoherency.co.uk">james@incoherency.co.uk</a>.
Also get in touch if you want to discuss something even if you will never hire me. I want to hear from you!
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/how-to-make-software-faster.html</link>
   <guid>http://incoherency.co.uk/blog/stories/how-to-make-software-faster.html</guid>
   <pubDate>Fri, 15 Apr 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Going Solo</title>
   <description><![CDATA[Today marks the last day of the "full-time job" stage of my career! For the foreseeable future, I'll be working
part-time for Netcraft. I will also be trying to find work freelancing (hire me!), and trying to make
more money from my other projects (e.g. ads on the Countdown Solver,
and selling SMS Travel Map subscriptions).]]></description>
   <content:encoded><![CDATA[<p>Today marks the last day of the "full-time job" stage of my career! For the foreseeable future, I'll be working
part-time for Netcraft. I will also be trying to find work freelancing (<a href="mailto:jes@jes.xxx">hire me!</a>), and trying to make
more money from my other projects (e.g. ads on the <a href="http://incoherency.co.uk/countdown">Countdown Solver</a>,
and selling <a href="http://smstravelmap.com/">SMS Travel Map</a> subscriptions).</p>
<p><a href="http://kalzumeus.com/">Patrick McKenzie</a> has a website full of good ideas for a "micro-Independent
Software Vendor", and I plan to apply as much of it as I can.</p>
<p>This change will also give me more time to tinker with the pit bike, decorate the house, make stuff in my garage, and generally enjoy more freedom.</p>
<p>Exciting times...
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/going-solo.html</link>
   <guid>http://incoherency.co.uk/blog/stories/going-solo.html</guid>
   <pubDate>Fri, 08 Apr 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to peek all of the jobs in a Beanstalk tube</title>
   <description><![CDATA[This problem came up at work today. There was a Beanstalk tube with a few hundred jobs in it, getting processed
slowly. A particular input didn't seem to be getting processed, and I wanted to know if it existed in the tube and
simply hadn't come out yet, or was missing entirely.]]></description>
   <content:encoded><![CDATA[<p>This problem came up at work today. There was a Beanstalk tube with a few hundred jobs in it, getting processed
slowly. A particular input didn't seem to be getting processed, and I wanted to know if it existed in the tube and
simply hadn't come out yet, or was missing entirely.</p>
<p>Googling the problem was not fruitful. A
<a href="http://stackoverflow.com/questions/4772770/how-can-i-get-a-list-of-all-jobs-in-a-beanstalk-tube">StackOverflow post from 2011</a>
was answered with "BeanstalkD is a queue - not an array, and not designed to
allow access to every item within it". Which is true, but not at all useful when
trying to debug a problem like this.</p>
<p>My solution was a Perl script to reserve all jobs in the tube, dump them as JSON, and then exit. Beanstalk implicitly
releases a job if the worker that has reserved it disconnects, so this means the program gets hold of every ready
job, and then they all return to the ready queue when it exits.</p>
<p><pre><code>#!/usr/bin/perl
    
use strict;
use warnings;
    
use Beanstalk::Client;
use JSON qw(encode_json);
    
my $q = Beanstalk::Client-&gt;new({ server => 'beanstalk-server.example.com' });
$q-&gt;watch_only('my_tube');
    
while (my $job = $q-&gt;reserve(1)) {
        print encode_json($job-&gt;args), "\n";
}</code></pre></p>
<p>The output is essentially in <a href="http://jsonlines.org/">JSON Lines</a> format.</p>
<p>Obviously, this is not applicable in all circumstances:</p>
<p><ol>
<li>if there are millions of large jobs, the program will run out of memory</li>
<li>jobs will get processed by other workers out-of-order because this program reserves and holds jobs from the front of the queue first</li>
<li>if there is never a second in which a job is not added, this program will never exit because it will never know when the queue is empty</li>
</ol></p>
<p>But it was useful for me, and it might be useful for you too.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/peek-all-beanstalk-jobs.html</link>
   <guid>http://incoherency.co.uk/blog/stories/peek-all-beanstalk-jobs.html</guid>
   <pubDate>Wed, 30 Mar 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I delivered 2 sofas for Vincent</title>
   <description><![CDATA[My phone rang early yesterday morning, while I was still basically asleep. A mobile
number I did not recognise. I answered. It was "Vincent". He asked me if I was free to deliver
2 sofas from Bristol to Weston-Super-Mare.
I groggily suggested 50 quid, with no idea how long it would take, and Vincent said he would be in touch.
I don't know where these people get my number from as I haven't had an ad for over 6 months...]]></description>
   <content:encoded><![CDATA[<p>My phone rang early yesterday morning, while I was still basically asleep. A mobile
number I did not recognise. I answered. It was "Vincent". He asked me if I was free to deliver
2 sofas from Bristol to Weston-Super-Mare.
I groggily suggested 50 quid, with no idea how long it would take, and Vincent said he would be in touch.
I don't know where these people get my number from as I haven't had an ad for over 6 months...</p>
<p>All morning, Vincent gave me the run around: "Can't get through to shop", "Not sure if shop is open today".
I thought he had bailed and was letting me down gently.</p>
<p>Around lunchtime, another call from Vincent: It's on.</p>
<p>There were no obvious staff at <a href="http://sofaproject.org.uk/">the SOFA Project</a>.
The back door was open. A mysterious hooded character stood outside, who turned out to be in charge.</p>
<p>The man wanted to see paperwork. I obviously didn't have any. He obviously over-estimated the operation I'm running.
He expressed doubts that the sofas would fit in my van.
He took a <i>lot</i> of my details down, clearly suspicious that I'd take the sofas and disappear.</p>
<p>Paperwork filled in, sofas on board, I hit the road once more.</p>
<p>I met Vincent outside his flat. It's a top-floor flat. Of course it is.
We heaved the first sofa up to the top floor, where disaster struck! The sofa was too big for Vincent's door. We tried every angle, but no dice.
Vincent suggested leaving it and he'd deal with it later. There's no way he'd get it through his door alone. He needed my help.
So I suggested taking the door off the hinges and Vincent agreed. With the door removed, we were able to move both sofas into his flat.</p>
<p>I re-fitted the hinges and disaster struck once more! The door had a
spring-loaded self-closing mechanism. I've never
encountered one before and it was too strong to prise open. I couldn't see how to get it back on.</p>
<p>Vincent said not to worry about it
and that he would get it fixed. I apologised a lot, but he said I'd done enough already.
(Done enough <i>damage</i> already?)</p>
<p>It was at this point that Vincent revealed he did not have any cash, and I must follow him to Morrisons where he would
withdraw some. He drove a silver Kia. Dodgy.</p>
<p>Despite his best efforts, Vincent did not manage to shake me off, and we rolled
in to Morrisons. Vincent, maverick, stopped his car in the middle of the road and walked to the cash machine. I parked.</p>
<p>I spotted Vincent walking to his car. I ran to catch up, lest he escape without paying. Vincent handed me &pound;60 in cash and we parted ways. He paid &pound;10 extra for all my hard work! What a legend.</p>
<p>It took 3 hours, so &pound;20/hr without counting diesel. And tax of course. Good adventure though, and Vincent was super cool.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/sofas-for-vincent.html</link>
   <guid>http://incoherency.co.uk/blog/stories/sofas-for-vincent.html</guid>
   <pubDate>Sun, 27 Mar 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to interrupt a regex in Perl</title>
   <description><![CDATA[Since 5.8.0, Perl's "safe signals" defers the delivery of signals
when a custom signal handler is in use,
until it is at a safe point to handle them. This means you can not simply use alarm()
to interrupt a long-running regex.]]></description>
   <content:encoded><![CDATA[<p>Since 5.8.0, Perl's "safe signals" <a href="http://perldoc.perl.org/perlipc.html#Deferred-Signals-%28Safe-Signals%29">defers the delivery of signals</a>
when a custom signal handler is in use,
until it is at a safe point to handle them. This means you can not simply use <tt>alarm()</tt>
to interrupt a long-running regex.</p>
<p>It is simple enough to create a child process to run the regex match, and use the default <tt>SIGALRM</tt> handler in the child
to allow it to be timed out. Here is an example function to run a regex match with a timeout:</p>
<p><pre><code>sub match {
    my ($string, $regex, $timeout_secs) = @_;
    
    my $pid = fork();
    die "can't fork: $!" if !defined $pid;
    
    if ($pid == 0) {
        # child process
        $SIG{ALRM} = 'DEFAULT';
        alarm $timeout_secs;
        
        exit(($string =~ $regex) ? 0 : 1);
    }
    
    # parent process
    waitpid($pid, 0);
    
    die "regex timed out\n" if $? & 0x7f;
    return !($? &gt;&gt; 8);
}</code></pre></p>
<p>This child process instates the default <tt>SIGALRM</tt> handler, starts an alarm, and checks if the string
matches the regex. It exits with 0 status if the string matches, and 1 otherwise.</p>
<p>The parent process waits for the child to exit. <tt>$?</tt> <a href="http://perldoc.perl.org/perlvar.html#%24CHILD_ERROR">is the exit status</a>.
"<tt>$? & 0x7f</tt>" tells us which signal, if any, the child died from (we just assume it was <tt>SIGALRM</tt>). "<tt>$? &gt;&gt; 8</tt>" tells
us the process exit status, which tells us whether the regex matched or not.</p>
<p>Given this information, the parent process either dies with <tt>"regex timed out\n"</tt>
or returns 1 if the regex matched and 0 otherwise.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/perl-interrupt-regex.html</link>
   <guid>http://incoherency.co.uk/blog/stories/perl-interrupt-regex.html</guid>
   <pubDate>Wed, 23 Mar 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to use GNU screen for ad-hoc cluster management</title>
   <description><![CDATA[If you have a cluster of machines, you can use GNU screen to run a management process on them all, monitor the output,
and manually take over and repair any issues that come up on any individual machine.]]></description>
   <content:encoded><![CDATA[<p>If you have a cluster of machines, you can use GNU screen to run a management process on them all, monitor the output,
and manually take over and repair any issues that come up on any individual machine.</p>
<p><h3>1.) Run screen with a named session</h3></p>
<p><pre><code>$ screen -d -m -S <b>jes</b></code></pre></p>
<p>This starts a detached screen session, named <tt><b>jes</b></tt>.</p>
<p><h3>2.) Create a window for each node of the cluster</h3></p>
<p><i>(Thanks Rich for pointing out <b><tt>seq -w</tt></b> can be used instead of <b><tt>--format=%02g</tt></b>)</i></p>
<p><pre><code>$ for i in <b>`seq -w 1 50`</b>; do
    screen -S <b>jes</b> -X screen ssh <b>node$i</b>
done</code></pre></p>
<p>This starts a new window for each node, inside the <b>jes</b> session, ssh'd into the node. Change the
<tt><b>`seq -w 1 50`</b></tt> to whatever is appropriate. If your nodes don't have predictable names
like this, something like <b><tt>for node in `cat nodelist`</tt></b> would suffice.</p>
<p><h3>3.) Type your command into the shell on each node</h3></p>
<p><pre><code>$ for i in `seq <b>1 50</b>`; do
    screen -S <b>jes</b> -p $i -X stuff "<b>ls\n</b>"
done</code></pre></p>
<p>The <b><tt>stuff</tt></b> command to screen tells it to insert the text as if it were typed. The "<b><tt>\n</tt></b>"
is needed, otherwise the "<b><tt>ls</tt></b>" would be typed but left at the input of the shell. This time you
must use "<b><tt>seq</tt></b>" (or similar...) as the windows in screen are numbered. The "<b><tt>-p $i</tt></b>"
argument tells screen which window to stuff the text into. The windows for your cluster nodes are numbered starting from 1. You'll also have a window 0 that is a shell on the local machine.</p>
<p>Run whatever it is you gotta run, instead of <b><tt>ls</tt></b>.</p>
<p><h3>4.) Attach to screen, monitor progress, and manually take over where necessary</h3></p>
<p><pre><code>$ screen -S <b>jes</b> -r</code></pre></p>
<p>This attaches you to the screen session. Initially you'll be shown the window of the last node. You can use it as
normal. E.g. <b><tt>^C</tt></b> if something goes wrong, and then you are in the shell and can do whatever you want.</p>
<p>You can repeatedly press <b><tt>C-a n</tt></b> to iterate through all of the windows and check on each one. Exit each one after you've finished with it to save yourself time.</p>
<p>Here is a screen cheatsheet that will help you navigate:</p>
<p><style type="text/css">
    td { padding-left: 5px; padding-right: 5px; }
</style></p>
<p><table border>
<tr><td>list windows</td><td><b><tt>C-a "</tt></b></td></tr>
<tr><td>switch window (0-9)</td><td><b><tt>C-a 0</tt></b>, <b><tt>C-a 1</tt></b>, etc.</td></tr>
<tr><td>detach from screen</td><td><b><tt>C-a d</tt></b></td></tr>
<tr><td>next/previous window</td><td><b><tt>C-a n</tt></b>, <b><tt>C-a p</tt></b></td></tr>
<tr><td>list screen sessions</td><td><b><tt>screen -ls</tt></b></td></tr>
</table></p>
<p><h3>How does this compare to <b><tt>clusterssh</tt></b>?</h3></p>
<p>It doesn't spawn a new terminal window for every node in your cluster. It also makes it easier to run a slightly different command on each machine by adjusting the content of the <b><tt>stuff</tt></b> in step 3. Apart from that, <b><tt>clusterssh</tt></b> is probably better.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/screen-cluster-management.html</link>
   <guid>http://incoherency.co.uk/blog/stories/screen-cluster-management.html</guid>
   <pubDate>Fri, 11 Mar 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I tried to go pit biking</title>
   <description><![CDATA[Tormarton pit bike track was finally open yesterday so I took my pit bike there.]]></description>
   <content:encoded><![CDATA[<p>Tormarton pit bike track was finally open yesterday so I took my pit bike there.</p>
<p>I did one lap, and then on the last corner I tried to brake but my brake did not
work and I went straight on and crashed in the weeds. Not injured.</p>
<p>I had a look at the rear brake. It is supposed to have 2 brake pads in it, but only
1 was present, and the other had worn most of the way through the backing plate.</p>
<p>I've fitted new pads and plan to try again next weekend.</p>
<p>I was not <i>completely</i> negligent: I did test the rear brake before riding the
bike. I should have had a look at the pads though. I think that when the bike was
rattling around on the track, one of the pads fell out (because it was worn down
so far) and just one pad is no use.</p>
<p>Also, when I tested the bike up and down the road, I used the rear brake and it was
good enough to lock up the wheel and do mad skids, despite having no friction
material.</p>
<p>Here is a picture of the brake pad:</p>
<p><img src="https://img.incoherency.co.uk/1178" width="500">
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/pitbiking.html</link>
   <guid>http://incoherency.co.uk/blog/stories/pitbiking.html</guid>
   <pubDate>Sun, 28 Feb 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made a video of driving my van</title>
   <description><![CDATA[I had an idea for a video series, where I put a camera in the passenger
seat of my van while I'm going places, and you listen to my anecdotes and
watch me driving, etc.]]></description>
   <content:encoded><![CDATA[<p>I had an idea for a video series, where I put a camera in the passenger
seat of my van while I'm going places, and you listen to my anecdotes and
watch me driving, etc.</p>
<p>I put the camera in and went to get some fish and chips, but it turns out
I'm not very chatty when it's just me. So there aren't any anecdotes.</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/bb0I2AO0QwE" frameborder="0" allowfullscreen></iframe>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/ride-wit-jes.html</link>
   <guid>http://incoherency.co.uk/blog/stories/ride-wit-jes.html</guid>
   <pubDate>Thu, 25 Feb 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I tried to change the glow plugs in my van</title>
   <description><![CDATA[My van has been tricky to start on cold mornings lately so I decided to try to replace the glow plugs.
I replaced 3 of the glow plugs. (There are 4).]]></description>
   <content:encoded><![CDATA[<p>My van has been tricky to start on cold mornings lately so I decided to try to replace the glow plugs.
I replaced 3 of the glow plugs. (There are 4).</p>
<p>One of the old glow plugs snapped off as I was unscrewing it!</p>
<p>I'm just going to leave it and hope it's fine.</p>
<p>I put the broken bits back on and wired it in as if it was fine.</p>
<p>So far the van runs fine so I'm calling it fine. It also starts better so at least one broken glow plug has been replaced.</p>
<p>A little bit worried that the snapped glow plug will fall out while I'm driving one day, so as insurance I'm keeping the remaining new plug and appropriate tools in the glovebox. But I think it's unlikely to fall out as it was easier to snap than unscrew.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/glow-plugs.html</link>
   <guid>http://incoherency.co.uk/blog/stories/glow-plugs.html</guid>
   <pubDate>Sat, 20 Feb 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I bought a pit bike</title>
   <description><![CDATA[I picked up a pit bike on Wednesday evening. It is basically an off-road mini moto. It cost &pound;250 and is a non-runner. Also the clutch lever is missing, the brake
lever falls outwards on its own, the chain is rusty, the tyres are worn out, there's lots of rust, one of the plastic panels is missing, the air filter is missing, the wiring
has obviously been mucked about with,
and the front brake did not work.]]></description>
   <content:encoded><![CDATA[<p>I picked up a pit bike on Wednesday evening. It is basically an off-road mini moto. It cost &pound;250 and is a non-runner. Also the clutch lever is missing, the brake
lever falls outwards on its own, the chain is rusty, the tyres are worn out, there's lots of rust, one of the plastic panels is missing, the air filter is missing, the wiring
has obviously been mucked about with,
and the front brake did not work.</p>
<p>I got up at 6.30am on Thursday to get 2 hours in the garage before work. During that time I determined that the bike does not run
because there is no spark. An almost-complete new electrical system was only &pound;17 on eBay so I ordered one.</p>
<p>Today I tried to adjust the valve clearances as I guessed they'd be out of spec. I took the cover off and found that the inlet valve adjuster
nut was missing! Not good news. Since the adjuster was free to move around on its own, the valve clearance was about 5mm. I've screwed the
adjuster in and set the clearance to the prescribed 0.10mm, and await delivery of a suitable nut. I just hope the old nut isn't still rattling around
inside somewhere. I can't explain how it got like this.</p>
<p>I would be surprised if the bike would run with 5mm of valve clearance, but there is evidence that it has done - there are marks
on the inside of the rocker cover from where the loose adjuster has been mashing against its lid. I don't imagine it was producing a lot of
power.</p>
<p>So current status is I'm going to replace the electrics and fit a nut to that valve adjuster. Then, fingers crossed, it might run...</p>
<p><img src="https://img.incoherency.co.uk/1166" width="500px"></p>
<p>(I've removed the fuel tank and plastics)
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/pit-bike.html</link>
   <guid>http://incoherency.co.uk/blog/stories/pit-bike.html</guid>
   <pubDate>Fri, 01 Jan 2016 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I rode my motorbike off road and made a video</title>
   <description><![CDATA[Lately I've been a bit interested in Green laning
on my motorbike.]]></description>
   <content:encoded><![CDATA[<p>Lately I've been a bit interested in <a href="https://en.wikipedia.org/wiki/Green_lane_%28road%29">Green laning</a>
on my motorbike.</p>
<p>The first couple of times I went, I just rode the bike as it normally is.</p>
<p>There were two problems: the tyres didn't grip off road, and the handlebars were too low.</p>
<p>The easiest way to ride over rough terrain is to stand up and let your knees bend, but with the
stupid clip-ons I'd put on the bike I had to be crouching forwards and it was really uncomfortable
and made my legs ache very quickly.</p>
<p>So I bought some motocross handlebars and some enduro tyres. To fit the handlebars I bought some appropriate
clamps and drilled a couple of holes in the top yoke, and simply bolted them on. That raised the bars by
about 3 inches, but also meant all the cables needed to be 3 inches longer, which I solved by just re-routing
the cables.</p>
<p>To fit a tyre you need to remove the old tyre from the wheel, and that means you need to break the "bead" - the
seal between the rubber tyre and metal wheel. There are proper tools for this, but I do not own one and do
not wish to buy one. I broke the bead by setting up the wheel in the vice, such that the front jaw is pushing
against the tyre. Against the back jaw I had a sheet of plywood so that the back jaw pushed against the whole
wheel rather than just the tyre. Tightening the vice thus squeezes one side of the tyre away from the wheel, and
the tyre eventually breaks free. Then just flip the tyre around and do the other side, and stamp on the tyre
a bit and it breaks free all the way around. I thought this was pretty clever. It still took me about 4 hours to
change both tyres though.</p>
<p>Anyway, today I went out for a quick ride on 3 green lanes near my house. On the first one I came across
the <a href="http://bristolmc.org.uk/allen-classic-trial/">Allen Classic Car Trial</a> coming the other way.
They didn't seem particularly pleased to see me, but it's essentially a public road so there's not much
they can do about it.</p>
<p>Feroz lent me his Garmin VIRB camera. The stickypad I put on the front mudguard seemed defective, not nearly
as sticky as the one I put on my helmet, and it fell off. Also, the microphone on the camera is awful,
loads of wind noise. Admittedly it was a windy day, but I'm pretty sure the
microphone on my phone is superior. The video quality was excellent though.</p>
<p>I then spent about 3 hours editing my 30 minutes of footage into a short video.</p>
<p>Here's my video:</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/ytbgPHkQB7A" frameborder="0" allowfullscreen></iframe>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/greenlaning.html</link>
   <guid>http://incoherency.co.uk/blog/stories/greenlaning.html</guid>
   <pubDate>Sun, 29 Nov 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made a gong</title>
   <description><![CDATA[Some colleagues at work somehow quickly became obsessed with gongs. So I made a gong. From brass.]]></description>
   <content:encoded><![CDATA[<p>Some colleagues at work somehow quickly became obsessed with gongs. So I made a gong. From brass.</p>
<p>I made the gong on Saturday, and live-streamed my work on Snapchat to the
rest of the gong owner's club. That was pretty fun. Unfortunately I concentrated more on sending
Snapchats than on taking photos for the blog, but never mind.</p>
<p>I bought a sheet of 2mm brass off ebay. I drilled a hole in the centre and screwed it to my work bench.
I then clamped a grinder to the bench such that it would cut the brass in a circle.</p>
<p><img src="https://img.incoherency.co.uk/1148" width="500px"></p>
<p>Running the grinder caused the brass to whizz round and round really fast, so I used my spare hand to slow
it down. Grinding through the brass took some time, but it worked pretty well. Then I just cleaned the edge
up with a file and had a pretty clean cut circle (albeit with a hole in the middle).</p>
<p><img src="https://img.incoherency.co.uk/1149" width="500px"></p>
<p>Next I made 16 radial marks around the perimeter of the circle, 3cm from the circumference towards the centre,
and cut the lines with a hacksaw. If I did this again I would measure the angles instead of guessing.</p>
<p>These cuts formed 16 tabs around the outside. I bent them over by pounding on them with a hammer, leaving each tab overlapping
the one before it. The last one was pretty tricky, I had to bend the first one back out a bit to get it underneath.</p>
<p>The brass had a good side (protected by some film) and a bad side. I accidentally bent the tabs the wrong way so the
good side was facing in. No big deal though.</p>
<p>Next I soldered the tabs together to give it a bit more rigidity. It was quite hard to solder as the brass is so big. I
used a pair of mole grips as a heat sink so that I could solder one tab without melting the previous one.
I also filled the hole in the centre with solder.</p>
<p><img src="https://img.incoherency.co.uk/1150" width="500px"></p>
<p>Next I smoothed the overlaps of the tabs. I initially tried using a file but it was taking ages so I used the grinder
instead.</p>
<p>I tried to stamp the name of the gong (Hardicanute) into the face but it came out rubbish so I sanded it back out
with emery paper.</p>
<p>I sanded the outer face (including sides) of the gong with 120, 320, and 600 grit emery paper to get rid of the
discolouration from soldering and polish it up a little bit (it could do with some proper polishing though),
before drilling a couple of holes and putting some string through.</p>
<p>The gong's voice has been described by a member of the gong owner's club as "a lovely rounded resonant sound".</p>
<p>I still need to build a frame and striker for the gong...</p>
<p><img src="https://img.incoherency.co.uk/1151" width="500px">
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/hardicanute.html</link>
   <guid>http://incoherency.co.uk/blog/stories/hardicanute.html</guid>
   <pubDate>Wed, 11 Nov 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made a puzzle game</title>
   <description><![CDATA[This evening I had an idea for a small puzzle game and implemented it.]]></description>
   <content:encoded><![CDATA[<p>This evening I had an idea for a small puzzle game and implemented it.</p>
<p>It is called <a href="http://jes.xxx/light-entertainment/">Light Entertainment</a>.</p>
<p>I don't want to give too much away because the aim of the game is to figure out
the rules, but the gist is you turn off a light, then another light turns off at
random, and this repeats until you either win or lose.</p>
<p>If you figure it out, please let me know. I'd be interested to hear about how you did it:
how long did it take? what wrong ideas seemed right at first? how enjoyable was the puzzle?</p>
<p>Also, by way of a small prize, I'll buy a pint for the first person to figure it out.</p>
<p>Good luck.</p>
<p><b>Update 2015-11-02:</b> Ben Gazzard has claimed the prize, congratulations Ben!
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/light-entertainment.html</link>
   <guid>http://incoherency.co.uk/blog/stories/light-entertainment.html</guid>
   <pubDate>Sun, 01 Nov 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>If you serve javascript with a 404 status does it still get executed?</title>
   <description><![CDATA[This topic came up at work today when we noticed a Javascript file was missing. Does the browser still try to
execute the 404 page that gets returned? And if not, would it if the Content-Type were set appropriately?]]></description>
   <content:encoded><![CDATA[<p>This topic came up at work today when we noticed a Javascript file was missing. Does the browser still try to
execute the 404 page that gets returned? And if not, would it if the <tt>Content-Type</tt> were set appropriately?</p>
<p>I set up a little test page like:
<pre><code>&lt;script src="js.cgi?status=404&amp;ctype=text/javascript"&gt;</code></pre></p>
<p>where <tt>js.cgi</tt> outputs text like:
<pre><code>document.write("Executed javascript for status=404 and content-type=text/javascript");</code></pre></p>
<p>so that I could test whether the code for a given <tt>Content-Type</tt> and status got executed.</p>
<p><tt>Content-Type</tt> didn't make any difference in any of my tests (i.e. <tt>text/html</tt> and <tt>text/javascript</tt> both
got Ignored or executed just the same).</p>
<p>Firefox executed any Javascript served with a 2xx status code, but not for 4xx or 5xx.
Chrome executed any Javascript served with a 2xx <b>or 3xx</b> status code, but not for 4xx or 5xx.</p>
<p>With the 3xx test, I returned the content exactly the same as for a 2xx response, including the lack
of a <tt>Location</tt> header, just to see how the browsers would react.</p>
<p>Neither browser executed code for 1xx statuses, or for 6xx.</p>
<p>Both browsers executed code for completely fictitious statuses, as long as they fell in 2xx (or 3xx for
Chrome) such as 293.</p>
<p>So the answers to our questions are: <b>no</b> the browser does not execute the 404 page, and <b>no</b>
it wouldn't even if it had a javascript <tt>Content-Type</tt>.</p>
<p>I found all this interesting. If you can shed more light on it, please give us a shout.</p>
<p>Cheers.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/javascript-404.html</link>
   <guid>http://incoherency.co.uk/blog/stories/javascript-404.html</guid>
   <pubDate>Wed, 07 Oct 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made a knife out of a file</title>
   <description><![CDATA[Since making a little knife out of a hacksaw blade a few weeks ago,
I've been working on a bigger knife made from a file.]]></description>
   <content:encoded><![CDATA[<p>Since making a <a href="https://incoherency.co.uk/blog/stories/little-knife.html">little knife out of a hacksaw blade</a> a few weeks ago,
I've been working on a bigger knife made from a file.</p>
<p><img src="https://img.incoherency.co.uk/1058" width="500"></p>
<p>I drew the outline of the knife on to the file, and ground it out.
I was careful not to let the file get too hot as this can apparently
ruin the hardening of the steel and keep it from holding an edge properly.
I just kept a glass of water by the grinder to dip the steel in every few seconds.</p>
<p><img src="https://img.incoherency.co.uk/1060" width="500"></p>
<p>The knife has what I believe is termed a "hollow grind".
I cut a block of wood at an angle and clamped the steel to it.
I them dragged the steel across the grinding wheel using the wood
to keep it square, hence forming a hollow grind.</p>
<p>At this point the surface of the file was still a file, which is not at all
helpful for a knife (perhaps a knife+file multitool? but that's another project).
I used the belt sander attachment on my grinder to take the teeth off the file.
I actually stopped a little short of completely removing the shape of
the teeth as I like the look of it.</p>
<p>I used some more of the oak offcuts I have to make the handle.
I tried to drill some holes through the tang to use pins to hold the handle on,
but the steel is unfortunately too hard! I expected to have trouble
drilling the holes but had no idea it would be this hard. I even heated
the tang up to the point where it changed colour in an effort to
ruin the hardening (who needs a hardened handle?) but to no avail.
The only outcome of my efforts toward drilling holes was a blunted
drill bit.</p>
<p><img src="https://img.incoherency.co.uk/1073" width="500"></p>
<p>No matter, I simply epoxied the oak to the tang with no pins.
Once the epoxy had dried, I shaped it on the belt sander. I removed the
"table" from the belt sander so that the belt could flex a bit to help
make the rounded edges. This worked better than expected.</p>
<p>Next I polished the blade a bit using a polishing wheel on my Dremel
(but it could have done with a bit more polishing). I tried to sharpen the blade but I am still rubbish at it. The knife is sharp enough
to get by but I wish I was able to sharpen knives better...</p>
<p>Finally I applied wax to the handle.</p>
<p><img src="https://img.incoherency.co.uk/1070" width="500"></p>
<p>The main mistake with this knife is that the point of the blade is not quite a point due to the wooden blocks method I used to grind it.
Ideally I would have kept the tangent of the edge of the blade parallel to the ground at the point of grinding, but I just kept the body of the blade parallel to the ground.</p>
<p>I'm pretty pleased with the result.
More pictures <a href="https://img.incoherency.co.uk/group/13.html">here</a>. I didn't take as many as I ought to have done.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/second-knife.html</link>
   <guid>http://incoherency.co.uk/blog/stories/second-knife.html</guid>
   <pubDate>Sun, 28 Jun 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Logrotate race condition with copytruncate</title>
   <description><![CDATA[The logrotate tool has a mode called copytruncate which copies the log file
and truncates the original, rather than renaming the original, so that the daemon doesn't need to reopen the log file.]]></description>
   <content:encoded><![CDATA[<p>The <tt>logrotate</tt> tool has a mode called <tt>copytruncate</tt> which copies the log file
and truncates the original, rather than renaming the original, so that the daemon doesn't need to reopen the log file.</p>
<p>I've long wondered how this is implemented without the obvious race
condition (i.e. log is copied, data is written, log is truncated -- the data written in the
middle would get lost with a naive implementation). Today I wanted to implement a similar
feature in a project at work, so I set about finding out how <tt>logrotate</tt> implements it.</p>
<p>I couldn't find any information online about avoiding the race condition so I read the source, and was
surprised to find no obvious tricks.
<tt>Logrotate</tt> just copies the log to the new file, then truncates the original file.
It simply ignores the race condition. In fact, on closer inspection, this is
even documented in the man page:</p>
<p><blockquote>
Truncate  the  original log file to zero size in place after creating a copy, instead of
moving the old log file and optionally creating a new one.  It can  be  used  when  some
program  cannot be told to close its logfile and thus might continue writing (appending)
to the previous log file forever.  Note that there is a very small  time  slice  between
copying  the  file  and  truncating  it,  so some logging data might be lost.  When this
option is used, the create option will have no effect, as the  old  log  file  stays  in
place.
</blockquote></p>
<p>I wrote a small C program to test it (outputting increasing numbers as fast as it could) and, indeed, 4 million lines
were lost during the course of the log rotation.</p>
<p>Much like with my previous post about <a href="https://incoherency.co.uk/blog/stories/digital-ocean-private-network.html">Digital Ocean private networking</a>,
this won't be a surprise to anyone who thoroughly reads the documentation, but I, for one, was surprised by <tt>logrotate</tt>'s
behaviour.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/logrotate-copytruncate-race-condition.html</link>
   <guid>http://incoherency.co.uk/blog/stories/logrotate-copytruncate-race-condition.html</guid>
   <pubDate>Thu, 11 Jun 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made a little knife</title>
   <description><![CDATA[I made a knife today. Just a little one, out of an old hacksaw blade.
Only half a hacksaw blade, I used the other half to make a gasket scraper (not pictured).]]></description>
   <content:encoded><![CDATA[<p>I made a knife today. Just a little one, out of an old hacksaw blade.
Only half a hacksaw blade, I used the other half to make a gasket scraper (not pictured).</p>
<p>I drew the outline of it on to the blade,
then ground the hacksaw blade down with the bench grinder
to make a knife "blank" (technical term), then ground a bit of a bevel onto the blade,
then polished the blade part of the blank a bit to make it less rusty and nasty, and
drilled an extra hole (the first one was already present from the hacksaw blade).</p>
<p><img src="https://img.incoherency.co.uk/1053" width="500"></p>
<p>I traced the outline of the handle onto two little pieces of oak I had lying around,
and cut it out vaguely.
I drilled some holes in the pieces of oak to match the holes in the tang
and held it together with drill bits while working on the general shape.</p>
<p><img src="https://img.incoherency.co.uk/1054" width="500"></p>
<p>I used superglue and some brass wood screws to attach the oak "scales" (technical term)
and I ground down the screw heads and tails (?) to make them flush with the oak
and rounded the corners of the oak on the belt sander.</p>
<p><img src="https://img.incoherency.co.uk/1055" width="500"></p>
<p>I sharpened the blade. It's not too sharp, because I am no good at sharpening knives.
I've never managed to sharpen a knife properly.</p>
<p>The handle is "finished" with engine oil and dirt.</p>
<p><img src="https://img.incoherency.co.uk/1056" width="500"></p>
<p>I left hacksaw teeth exposed on the spine of the blade, looks pretty cool.</p>
<p>This knife was just a practise, I intend to make a big-ass knife out of an old file at some point.</p>
<p><img src="https://img.incoherency.co.uk/1057" width="500">
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/little-knife.html</link>
   <guid>http://incoherency.co.uk/blog/stories/little-knife.html</guid>
   <pubDate>Sun, 31 May 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made a plymetal heart decoration</title>
   <description><![CDATA[This evening I had an idea for making an effect like plywood, but out of metals (hence "plymetal"). I tried it
out to make a little heart decoration and it worked great, although I did a poor job.]]></description>
   <content:encoded><![CDATA[<p>This evening I had an idea for making an effect like plywood, but out of metals (hence "plymetal"). I tried it
out to make a little heart decoration and it worked great, although I did a poor job.</p>
<p>The effect is of having several alternating layers of different metals (I used copper and brass), achieved by soldering them together.</p>
<p>Regretfully I did not take photos while I was working (I wasn't initially planning to blog about it, but I liked how it turned
out). Here are the steps to making the plymetal:</p>
<p>1.) Cut sheets to roughly similar size (do this well otherwise your sheets might not be big enough and gaps will be visible
in the finished product - like with mine).</p>
<p>2.) For each little square you have (except leave one alone): apply flux to one side, then heat it up with a blow torch and cover the side
in solder as best you can (try to do a good job else gaps might be visible in the finished product - like with mine). Now you have N sheets, N-1 of which are tinned on one side.</p>
<p>3.) Stack the sheets up so that there is a tinned side between every adjacent pair (this is why you only tinned N-1:
for N stacked sheets there are N-1 gap layers), with a layer of flux between each sheet - the flux will help the solder flow and also kinda sticks the sheets together.</p>
<p>4.) Clamp the sheets together strongly (do it stronger than I did else it is harder to get the solder to flow and can cause gaps - like with mine) but also try to have as little surface area touching the clamps as possible (the clamp acts as a heat sink making it difficult to solder).</p>
<p>5.) Now hold the piece level (i.e. so that the solder planes are parallel to the ground - I messed this up and a lot of solder dripped out the bottom) and heat the whole thing up with a blow torch until you're pretty sure the solder has become molten everywhere.</p>
<p>6.) Wait for it to cool down (light spraying of water to speed the process is fine, but probably best not to do too much).</p>
<p>7.) You now have a block made of different metals stuck together! Draw a heart (or any shape), cut it out, file the edges, sand, polish, drill hole, tie a knot in some string, take photo. About 3 hours' work.</p>
<p><img width="500" src="https://img.incoherency.co.uk/1030/">
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/heart-decoration.html</link>
   <guid>http://incoherency.co.uk/blog/stories/heart-decoration.html</guid>
   <pubDate>Sun, 26 Apr 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I painted my van wheels</title>
   <description><![CDATA[My van has steel wheels and they were pretty rusty so I decided to paint them.]]></description>
   <content:encoded><![CDATA[<p>My van has steel wheels and they were pretty rusty so I decided to paint them.</p>
<p>I took a <a href="https://img.incoherency.co.uk/group/9.html">selection of photos</a> throughout the process.</p>
<p>On Sunday I put the van on jacks and axle stands, took all the wheels off, and cleaned, stripped, masked,
and primered them. I stripped the old rust/paint with a wire brush mounted in my drill. This is
an excellent tool, far superior to wire brushing by hand. I masked the wheels with masking tape
and newspaper, taking care to mask off the valve stems neatly. I then sprayed the primer that I already
had lying around. I spent about 3 hours just preparing the wheels to be painted.</p>
<p>Then I had to wait for the paint to arrive (I stupidly ordered the paint off the Internet), which meant my
van was sitting around all week with no wheels on. This was bad, I should have planned better.</p>
<p>Anyway my paint arrived yesterday and I painted the wheels yesterday evening and re-fitted them this morning.
They look pretty sweet. The colour is "Anthracite Technik Grey". Of course.</p>
<p><img src="https://img.incoherency.co.uk/1016" width="500"></p>
<p><img src="https://img.incoherency.co.uk/1020" width="500"></p>
<p><img src="https://img.incoherency.co.uk/1021" width="500">
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/van-wheels.html</link>
   <guid>http://incoherency.co.uk/blog/stories/van-wheels.html</guid>
   <pubDate>Sat, 11 Apr 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to close a running process's socket</title>
   <description><![CDATA[I had a problem this morning of a process that was stuck waiting for an HTTP fetch
to complete, and had been stuck for 8 hours. Obviously the fetch had not been successful,
and additionally some sort of timeout
had broken, but I wanted the process to continue executing for the time being. What to do?]]></description>
   <content:encoded><![CDATA[<p>I had a problem this morning of a process that was stuck waiting for an HTTP fetch
to complete, and had been stuck for 8 hours. Obviously the fetch had not been successful,
and additionally some sort of timeout
had broken, but I wanted the process to continue executing for the time being. What to do?</p>
<p>(This particular program was a Perl program, but I don't see why the same technique doesn't apply
to almost anything).</p>
<p>Obviously the fetch is not going to complete successfully, but that's OK, the program
in question is designed to tolerate failed fetches. If we could only close the socket it's
trying to read, the read would return and the process would continue. It turns out that's
quite easy.</p>
<p>First, find the file descriptor of the socket. In my case, the remote host is known
as it is shown in the last line of our process's log output (it's <tt>gingerspice.example.com</tt>), and the PID (10029) is derived in any number of
ways (the pidfile, <tt>ps</tt>, <tt>pgrep</tt>, whatever).</p>
<p><pre><code>[jes@scaryspice ~]$ sudo lsof -p 10029 | grep gingerspice
perl    10029 nobody   4u  IPv4 51480959      0t0      TCP scaryspice.example.com:59521->gingerspice.example.com:11014 (ESTABLISHED)</code></pre></p>
<p>So there we see the file descriptor is 4 (that's the "4u" column). Now we want to
attach to the process with <tt>gdb</tt>:</p>
<p>
<pre><code>[jes@scaryspice ~]$ sudo gdb /usr/bin/perl 10029
GNU gdb (GDB) CentOS</p>
<p>[...]</p>
<p>warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7fff28c52000
0x000000339d80da70 in __read_nocancel () from /lib64/libpthread.so.0
(gdb) </code></pre></p>
<p>(I redacted a whole load of boring output there). We can see the process was in the <tt>__read_nocancel</tt>
function from <tt>libpthread</tt>, this is consistent with our understanding that it was blocked on a read.</p>
<p>Now, using the <tt>gdb</tt> shell, we simply close the file descriptor and detach our debugger, and then the read will return
and execution will continue:</p>
<p><pre><code>(gdb) call close(4)
$1 = 0
(gdb) quit
A debugging session is active.</p>
<p>    Inferior 1 [process 10029] will be detached.</p>
<p>Quit anyway? (y or n) y
Detaching from program: /usr/bin/perl, process 10029
[jes@scaryspice ~]$ </code></pre></p>
<p>And now our HTTP fetching program continues on its merry way! Hope this is useful to someone. Give us a shout if there's
a better way to do it.</p>
<p>Cheers.</p>
<p><b>Update 2015-04-11:</b> Marko points out you can use <pre><code>gdb -p 10029 --batch -ex 'call close(4)'</code></pre>
to close the socket in one go without invoking the <tt>gdb</tt> shell.</p>
<p><b>Update 2015-04-13:</b> Jilles Tjoelker (<a href="http://www.stack.nl/~jilles/">http://www.stack.nl/~jilles/</a>) adds:</p>
<p><blockquote>I noticed your technique can be dangerous when used on multi-threaded
applications. If another thread opens a new file descriptor and gets the
same descriptor number as the forcibly closed hung connection, the
originally hung thread might perform operations on it, which then affect
the new object. When the forcibly closed connection is closed normally,
the new file descriptor is actually closed, and the other thread will
not work properly. If new file descriptors are opened frequently, the
"poisoning" can spread, receiving and sending data from and to the wrong
place.
<br><br>
Fortunately, there is an easy solution for sockets: use shutdown()
instead of close(), for example 'call shutdown(4, 2)'. The shutdown()
function closes the connection (or one direction of the connection),
while keeping the socket valid. Also, it actually wakes up threads in a
blocking operation in most implementations, where the close() probably
relies on the debugger forcing all threads to the user boundary
(restarting all system calls and refetching the underlying objects from
all file descriptors).
<br><br>
Some operating systems such as FreeBSD and OpenBSD have a tcpdrop(8)
utility to close a TCP connection without needing to attach a debugger
(which is always a somewhat risky operation).
</blockquote>
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/closing-a-socket.html</link>
   <guid>http://incoherency.co.uk/blog/stories/closing-a-socket.html</guid>
   <pubDate>Thu, 09 Apr 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I drove a truck and bought a car</title>
   <description><![CDATA[Yesterday me and Emma went to pick up a Nissan Micra I bought off eBay
for £375. We currently have no intention of taxing or insuring the car
as she needs to learn to drive first, and I didn't feel comfortable
driving the car all the way back with no tax or insurance.]]></description>
   <content:encoded><![CDATA[<p>Yesterday me and Emma went to pick up a Nissan Micra I bought off eBay
for £375. We currently have no intention of taxing or insuring the car
as she needs to learn to drive first, and I didn't feel comfortable
driving the car all the way back with no tax or insurance.</p>
<p>That meant I got to hire a car transporter truck, and drive it around
for the day. It was an '08 Mercedes Sprinter. It was awesome.
It beeped when reversing and everything.</p>
<p>The worst moment was stalling it in the middle of a roundabout and not
being able to figure out how to restart it. For whatever reason, you have to
wait a long time before the truck is willing to restart, pretty embarrassing.</p>
<p>The Micra is pretty good too, absolute bargain for £375. It has done only
44k miles, and has no evidence of ever having an oil leak, and no rusty
bodywork. The only problem is the doors don't quite fit, the latches clunk
as the doors close. I have vague plans to try and adjust this, but won't
be too bothered if I can't fix it.</p>
<p>Here are some pictures for your enjoyment:</p>
<p><img src="https://img.incoherency.co.uk/1008" width="500"></p>
<p><img src="https://img.incoherency.co.uk/1009" width="500"></p>
<p><img src="https://img.incoherency.co.uk/1010" width="500">
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/truck-driving.html</link>
   <guid>http://incoherency.co.uk/blog/stories/truck-driving.html</guid>
   <pubDate>Mon, 23 Mar 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Digital Ocean Private Networking is not Private</title>
   <description><![CDATA[Digital Ocean offer a "Private Networking" option which, to many people, sounds like
it is accessible only to other droplets created by the same Digital Ocean account.]]></description>
   <content:encoded><![CDATA[<p>Digital Ocean offer a "Private Networking" option which, to many people, sounds like
it is accessible only to other droplets created by the same Digital Ocean account.</p>
<p>A coworker recently explained to me that this is not how it works.</p>
<p>The "Private Networking" mode is actually a network shared across every droplet in the same Digital Ocean datacentre!
There are likely a large number of people who assume they can use Private Networking to keep services private,
but are unwittingly exposing themselves to attack by any interested party.</p>
<p>So, if you use Digital Ocean's Private Networking for privacy purposes: you should stop right away
and set up something else! Possibilities including setting up stunnel, or OpenVPN, or SSH tunnels.
Feel free to get in touch if you need more information.</p>
<p>In Digital Ocean's defence, nowhere do they state that their Private Networking mode provides privacy.
In <a href="https://www.digitalocean.com/company/blog/introducing-private-networking/">the Private
Networking announcement</a>, they do describe it as "Shared Private Networking", though they do not make it explicit
that it is shared with droplets belonging to other users.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/digital-ocean-private-network.html</link>
   <guid>http://incoherency.co.uk/blog/stories/digital-ocean-private-network.html</guid>
   <pubDate>Thu, 05 Mar 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I built a campervan</title>
   <description><![CDATA[I took today off work to work on the interior of my van. I intend to use the van as a camper van, but my main priority
is that it can still be used as a normal van. I don't go in for these camper van designs that leave no usable space
(e.g. to carry a motorbike, or a secondhand sofa). Martin gave me a futon, which is brilliant - it is basically an
instant camper van as it provides seating and bedding in one.]]></description>
   <content:encoded><![CDATA[<p>I took today off work to work on the interior of my van. I intend to use the van as a camper van, but my main priority
is that it can still be used as a normal van. I don't go in for these camper van designs that leave no usable space
(e.g. to carry a motorbike, or a secondhand sofa). Martin gave me a futon, which is brilliant - it is basically an
instant camper van as it provides seating and bedding in one.</p>
<p>I ply-lined the walls of the van on Sunday, so I had a good place to start. I built a frame for a shelving unit and panelled
it with plywood, and screwed it to the wall. The shelving unit is designed so as to take up minimal floor space (i.e. stay
flush with the wheel arch), which means it's not as big as most van shelving units, but allows the futon to fit in bed formation.</p>
<p>I am ridiculously pleased with the shelving, it turned out a lot better than I expected.</p>
<p>I picked up a sewing machine on Gumtree for £10 a few weeks ago. The machine was mis-timed initially, but I fiddled with
it over a few evenings and eventually got it to sew. The curtains in
the van are the first thing that's been sewed since I got the machine, aside from test pieces. It turns out I'm
rubbish at sewing, but it should do the job.</p>
<p>I intend to put a fold-down worktop on the unused wall. I have a gas camping stove but currently have nothing to put it on,
so it'll probably be going on the floor until I've built a worktop.</p>
<p>I took lots of <a href="https://img.incoherency.co.uk/group/7.html">pictures as I was building things</a>.</p>
<p>Here are a some pictures of the van as it stands now:</p>
<p><img src="https://img.incoherency.co.uk/1000" width="500"></p>
<p><img src="https://img.incoherency.co.uk/1001" width="500"></p>
<p><img src="https://img.incoherency.co.uk/1002" width="500">
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/van-interior.html</link>
   <guid>http://incoherency.co.uk/blog/stories/van-interior.html</guid>
   <pubDate>Thu, 26 Feb 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I am back on the bike</title>
   <description><![CDATA[I ride a 1989 Honda VFR750F. It's a brilliant bike, but has had very tatty fairings due to being knocked over several times.]]></description>
   <content:encoded><![CDATA[<p>I ride a 1989 Honda VFR750F. It's a brilliant bike, but has had very tatty fairings due to being knocked over several times.</p>
<p>The following is a picture of the bike about a year ago, loaded into my comically-small Hijet van ready for a trackday. If you imagine a
bunch more cracks in the fairing, you can get the idea.</p>
<p><img src="https://img.incoherency.co.uk/760" width="400"></p>
<p>A few months ago I started converting the bike to a naked look. All that
happened though was that I took the fairings off and subsequently had nowhere to mount the original mirrors and lights.
So the bike has been off the road ever since.</p>
<p>The oil cooler used to mount inside the front cowl of the fairing, in front of the forks. Obviously
this wouldn't suit the more minimal look, so I relocated it to sit just underneath the radiator (see pic at end). It's not fitted very
well but without buying new hoses my options for locating it were pretty limited.</p>
<p>The fuse box and most of the electrical connectors also used to mount inside the front cowl. This, too, would look
ungainly without a fairing to hide it, so the electrical stuff has been relocated inside the frame, underneath the
tank. The original airbox is pretty big and used to fill the room here, so I had a cunning plan to make some minimal
air filters.</p>
<p>I cut out some little pieces of sponge and held them in front of the carburettors with carefully-shaped lockwire.</p>
<p><img src="https://img.incoherency.co.uk/932" width="400"></p>
<p>I unfortunately didn't have enough foam so the top-right carb in pic has some layers of cloth instead (I intended to buy more foam
if the mod was a success). As it turned out, these air filters were shit and severely restricted the power. In the end I went with
the original airbox, but with the top part removed to make room for the wiring. I'd like to add the top part again as I think the
power is still a little restricted but it will need a rethink of the wiring as there currently isn't room. </p>
<p>This is how the bike looks now:</p>
<p><img src="https://img.incoherency.co.uk/982" width="400">
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/motorbike.html</link>
   <guid>http://incoherency.co.uk/blog/stories/motorbike.html</guid>
   <pubDate>Sun, 15 Feb 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I built an oak chest</title>
   <description><![CDATA[Since the start of the year I've been spending some time at weekends building an oak storage chest.]]></description>
   <content:encoded><![CDATA[<p>Since the start of the year I've been spending some time at weekends building an oak storage chest.</p>
<p>I finished building the box on my day off on Wednesday and have been waxing it today.</p>
<p>It's made of inch-thick oak planks which I bought off the internet. In hindsight, I should have used
thinner wood. This is extremely heavy and expensive (I spent £150 on wood alone, and it was only roughly cut,
and some planks were a little warped). Most of my time was spent preparing the wood as it was so rough
when it arrived. I think the wood was intended for constructing things, not making furniture.</p>
<p>Jez lent me a power planer which was very useful in preparing the wood, even if I wasn't very good at operating it.</p>
<p>The box is entirely constructed using screws and steel brackets. I used this construction because I'm not good
enough at woodwork to make nice joints and glue them, but I still didn't want screws showing from the outside. The following
picture shows the brackets I used.</p>
<p><img src="https://img.incoherency.co.uk/939" width="500"></p>
<p>The lid consists of two planks held together on the bottom with metal straps. I wasn't sure this was going to be strong enough to
keep the lid from bending but it seems fine. For the hinges, I initially bought some furniture hinges off eBay, but it was clear
they were not up to the task. I then bought some larger hinges off eBay, but even they seemed a bit flimsy. I subsequently found
some huge hinges at B&Q, and these are what I fitted.</p>
<p>The hinges didn't have a round hole near the "hinge" part initially (there is a square hole which I do not understand the purpose for,
and which is too big), so I drilled an extra hole. They are excellent hinges.</p>
<p><img src="https://img.incoherency.co.uk/943" width="500"></p>
<p>I bought some handles and brass corner pieces off eBay, which I think are quite nice.</p>
<p>In total there are about 250 screws in the box!</p>
<p>Once the box was constructed, I still had to carry it from my garage to my house. This is not easy as I can barely lift the box.
Fortunately, I have acquired a shopping trolley, which I used to move the box.</p>
<p><img src="https://img.incoherency.co.uk/964" width="500"></p>
<p>And here's the box in position with two coats of wax:</p>
<p><img src="https://img.incoherency.co.uk/973" width="500">
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/oak-chest.html</link>
   <guid>http://incoherency.co.uk/blog/stories/oak-chest.html</guid>
   <pubDate>Sun, 08 Feb 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>How to make driftwood sink</title>
   <description><![CDATA[I went to the seaside on Sunday and picked up some driftwood to put in my fish tank.]]></description>
   <content:encoded><![CDATA[<p>I went to the seaside on Sunday and picked up some driftwood to put in my fish tank.</p>
<p>I went to wash the wood beforehand in my sink and, much to my dismay, the wood floated.
In hindsight this seems obvious:</p>
<p>a.) wood floats</p>
<p>b.) it wouldn't wash up on the beach if it didn't float</p>
<p>I felt like a muppet.
Anyway, I got on the Googles and found some people mentioned boiling it to make it get soaked with water so it sinks.
I boiled it for like 2 hours while playing Monopoly, and at the end just as I was ready to give up, I turned the hob off and put it in some cold water to cool it down.
And it sank!</p>
<p>So now there's some driftwood in my tank.</p>
<p><img src="https://img.incoherency.co.uk/953" width="500"></p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/driftwood.html</link>
   <guid>http://incoherency.co.uk/blog/stories/driftwood.html</guid>
   <pubDate>Tue, 03 Feb 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I bought some fish</title>
   <description><![CDATA[On Thursday I bought 3 fish. The biggest one is a barb, and I can't remember what the other two are.]]></description>
   <content:encoded><![CDATA[<p>On Thursday I bought 3 fish. The biggest one is a barb, and I can't remember what the other two are.</p>
<p>The biggest one and the brown spotty one are having a good time swimming around. Great success.</p>
<p>The black and orange one has just been sitting around in the corner and looked like he was going to die soon.
Raz suggested he might be a tropical fish, so I moved him to a pint glass on a radiator and he seems to have perked up.
My plan is to keep him on the radiator. The heating is only on during morning and evening but at least he should get a
bit more warmth than in the tank with the other fish. </p>
<p>Also, I initially had a toy motorbike and an old hard disk as tank decorations, but it was suggested that these might leak poisonous corrosion into the
water so I've removed them and am awaiting the delivery of some proper tank decorations.</p>
<p>This picture shows the 3 fish (black and orange one is hiding, at bottom left):</p>
<p><img src="https://img.incoherency.co.uk/947" width="500">
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/fish.html</link>
   <guid>http://incoherency.co.uk/blog/stories/fish.html</guid>
   <pubDate>Sat, 31 Jan 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made a ring out of a coin</title>
   <description><![CDATA[Around the start of this month I made a ring for Emma.]]></description>
   <content:encoded><![CDATA[<p>Around the start of this month I made a ring for Emma.</p>
<p>It is made from a 5 Ruble coin that I picked up during the Mongol Rally.</p>
<p>The general idea is to hit the edge of the coin with a hammer over and over again until the edge flattens over to the desired degree, then drill a hole in the middle, then file the hole out to the edges, then polish it up to get a nice finish.</p>
<p>I was disappointed to find that the 5 Ruble coin is merely "cupronickel-plated" and is actually made of Copper. This resulted in a rather different look to what I was going for. Still good though.</p>
<p>You can watch a video of a man making a coin the same way here: <a href="https://www.youtube.com/watch?v=548qCuDHe_Q">https://www.youtube.com/watch?v=548qCuDHe_Q</a>.</p>
<p>You can see all the photos I took <a href="https://img.incoherency.co.uk/group/5.html">here</a>.</p>
<p>And this is how it turned out:</p>
<p><img src="https://img.incoherency.co.uk/917" width="500">
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/ring.html</link>
   <guid>http://incoherency.co.uk/blog/stories/ring.html</guid>
   <pubDate>Tue, 27 Jan 2015 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I drove in the snow</title>
   <description><![CDATA[Yesterday I drove my new van up North to visit Emma. Halfway
through it started to snow.]]></description>
   <content:encoded><![CDATA[<p>Yesterday I drove my new van up North to visit Emma. Halfway
through it started to snow.</p>
<p>My van was plenty manageable despite being rear wheel
drive and with no weight in the back. The tyres have deep tread on which must have helped.</p>
<p>The M1 was being used as a single lane road, everyone driving in the middle lane so that if they spin out they're less likely to hit any Armco.
I did see one car spin a little but the driver saved it.</p>
<p>Coming up the slip road off the M1 was the first tricky part. There were a couple of lorries stuck unable to get up the hill, but the van coped OK and there was plenty of room to pass the lorries.</p>
<p>Some time later I came across a section of road where cars
were turning round and a traffic cop was standing in the road.
I elected not to stop or turn around and drove straight past the copper,
who obviously thought I knew what I was doing as he didn't try to stop me.
The snow got deeper but still drivable.</p>
<p>Then I came across stationary traffic due to a jack knifed lorry. Eventually they shifted the lorry but it was on a hill and lots of cars were getting stuck on the hill. I lent a hand pushing cars that were in my way and eventually got over the crest of the hill.
As traffic started to flow I came across a pedestrian walking along the road
and offered him a lift.</p>
<p>My passenger turned out to be a drug dealer, he made extensive use of phrases like "safe blud" and had 3 mobile phones, with which he received
at least 2 phone calls during the 10 minutes I observed him.
Friendly enough chap though.</p>
<p>I finally got stuck up a hill about 5 minutes' walk from
my destination. I "parked" (some might say "abandoned")
the van at the bottom of the hill and walked the final 5 minutes.</p>
<p>When I started the journey it was barely drizzling and the
sat nav predicted 2h30. By the time I arrived it was 6h30 later and there had been 6 inches of snow. Pretty fun though.</p>
<p><img src="https://img.incoherency.co.uk/911" width="500">
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/snow-driving.html</link>
   <guid>http://incoherency.co.uk/blog/stories/snow-driving.html</guid>
   <pubDate>Sat, 27 Dec 2014 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>SMS Travel Map</title>
   <description><![CDATA[As I mentioned before, I built an SMS-updating coordinate-tracking
system to use on the Mongol Rally so that everyone left behind could keep track of our progress.]]></description>
   <content:encoded><![CDATA[<p>As I mentioned <a href="https://incoherency.co.uk/blog/stories/yurt-lush-coordinates.html">before</a>, I built an SMS-updating coordinate-tracking
system to use on the Mongol Rally so that everyone left behind could keep track of our progress.</p>
<p>This turned out to be rather popular, and I realised it would be useful for a wider audience.</p>
<p>As such, after getting back from the rally, I've slowly been working on exactly such a service:
<a href="http://smstravelmap.com/">SMS Travel Map</a>.</p>
<p>The backend is now based on <a href="http://mojolicio.us/">Mojolicious</a> rather than CGI scripts, there
is a user interface to get information, signup and manage your maps, and there is a mechanism to identify
which map an SMS should go to (previously there was only one map, so every update went to the same map).</p>
<p>It's available and working now.</p>
<p>I also have plans to start using <a href="https://www.docker.com/">Docker</a>, and when I get time I
intend to transition SMS Travel Map over to running on Docker, along with various other projects I've
done. That would also be a good excuse to make <a href="https://github.com/jes/guess-whom">Guess Whom</a>
and <a href="https://github.com/jes/xory">Xory</a> live again.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/sms-travel-map.html</link>
   <guid>http://incoherency.co.uk/blog/stories/sms-travel-map.html</guid>
   <pubDate>Sat, 06 Dec 2014 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Stories from the Mongol Rally: Mongolian Black Market Pickpocket</title>
   <description><![CDATA[After completing the rally, and during our time as regular tourists in Ulaanbaatar, we visited a
large market known as the "black market".]]></description>
   <content:encoded><![CDATA[<p>After completing the rally, and during our time as regular tourists in Ulaanbaatar, we visited a
large market known as the "black market".</p>
<p>I had $200 in cash in my wallet, so I had intended to stash it somewhere at the hotel. However I forgot,
and arrived at the market with the cash still on my person. I moved my wallet from my back trouser
pocket to my front pocket so that I could keep an eye on it better.</p>
<p>After we'd been perusing the market for some time, a man pushed past me rather rudely (which wasn't
unusual in the black market - the locals were extremely rude). I immediately checked my pocket and
noticed that my wallet was gone!</p>
<p>I turned around and the guy was still near me due to the density of people in the market. Without
thinking, I thumped the guy in the stomach (as hard as I could at such short notice). He turned around
and looked at me, and I demanded that he
return my wallet. Even though he obviously wouldn't understand English, I was pretty sure he'd get the
gist. He shoved me in the stomach with both
hands, and pointed at the ground. My wallet was there on the floor, so I picked it up, thanked him,
and carried on.</p>
<p>I guess he must have shoved me with both hands as a way to direct attention away from the fact that he
was dropping my wallet on the floor.</p>
<p>Anyway I felt like a god and continue to tell people that I once beat up a hardened Mongolian criminal
for $200.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/mongolian-black-market-pickpocket.html</link>
   <guid>http://incoherency.co.uk/blog/stories/mongolian-black-market-pickpocket.html</guid>
   <pubDate>Wed, 19 Nov 2014 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Stories from the Mongol Rally: Kazakhstan Policeman Selfie</title>
   <description><![CDATA[Within about half an hour of getting into Kazakhstan, we were pulled over by the filth. We were
travelling with an American team, 3FLP, by this point.]]></description>
   <content:encoded><![CDATA[<p>Within about half an hour of getting into Kazakhstan, we were pulled over by the filth. We were
travelling with an American team, 3FLP, by this point.</p>
<p>The police did not speak any English, but indicated that we needed to turn our headlights on, even
in the daytime. Fair enough. We turned them on and were ready to drive away.</p>
<p>This did not placate our policeman, who insisted that we get out of the car and give him our
documents (our confusion about exactly <i>which</i> documents was merely met with further shouts of "document! document!").
We presented him with international driver's permits (which do not hold any legal standing anywhere in
the world), and he seemed happy.</p>
<p>He walked us to his car and told us we needed to pay $200.
Half-jokingly, I suggested $10. He countered my offer with $50, which made it clear that this was a
bribe and not a fine, and signalled that we did not actually have to pay it at all. The back and forth
about the "fine" continued for some time, and eventually (understanding that the copper did not
speak English) I said to him "look, I'm British, I don't have to deal with your shit, I'm going to get
back in my car and drive off". I took back my driving licence, got back in my car, and started it up.
The policeman also started his car up, and began shouting things over his loudspeaker. It was clear that
he was going to pursue us, which I was excited for, but Rory pointed out that this probably wouldn't end
well for us so I got back out of the car.</p>
<p>Now the policeman demanded to see my mobile phone (I guess he was intending to call someone who would
speak English at me). I retrieved my mobile phone and went back to his car. Having lost any sense of
seriousness, I took a sweet-ass selfie of me and this policeman, which seemed to annoy him a bit.
He wanted me to give the phone to him so I demanded that he give me his phone, assuming he would refuse.
He gave me his iPhone, I gave him my Nexus 4 and felt like we'd had a fair trade. He started looking
through the photographs on my phone, so I looked through the photographs on his. He didn't have many
so I took some more for him, mostly selfies of me and pictures of our car and the Americans' car.</p>
<p>While playing with the man's iPhone I was not paying attention to what he was doing on mine. Eventually
he gave me my phone back and I returned his. The American's gave him a couple of Mongol Rally dog tags
and we shook hands and were allowed to leave (it seems taking the selfie had reduced the price from $200
to "delete the selfie, plus 2 dog tags").</p>
<p>To my chagrin, it turned out that the policeman had deleted the selfie I took. I strongly regret not
installing some sort of app that would keep a secret copy of every picture that is taken.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/kazakhstan-policeman-selfie.html</link>
   <guid>http://incoherency.co.uk/blog/stories/kazakhstan-policeman-selfie.html</guid>
   <pubDate>Tue, 18 Nov 2014 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Stories from the Mongol Rally: the Georgian Diesel Incident</title>
   <description><![CDATA[Shortly after we got into Georgia, we pulled into a petrol station to fuel up the car. The writing
in this country uses these Georgian squiggles
so it is impossible to even pronounce the words. Fortunately, most of the pumps in this petrol station
also had writing in Latin, and we determined that the green pumps (like in Europe) pump petrol. So far, so good.]]></description>
   <content:encoded><![CDATA[<p>Shortly after we got into Georgia, we pulled into a petrol station to fuel up the car. The writing
in this country uses these <a href="http://en.wikipedia.org/wiki/Georgian_scripts">Georgian squiggles</a>
so it is impossible to even pronounce the words. Fortunately, most of the pumps in this petrol station
also had writing in Latin, and we determined that the green pumps (like in Europe) pump petrol. So far, so good.</p>
<p>So we parked next to the only free green pump and began fuelling. A short while later, the petrol station
attendant ran over shouting "Diesel! Diesel!" He seemed very concerned. I put the pumping nozzle back in
its holder and tried to explain that I hadn't pumped very much and I would fill the rest with petrol. This
man did not speak English and was getting rather excited by this point, even gesturing under the car -
presumably saying something about draining the tank.</p>
<p>Anyway we eventually convinced him that the car would run fine with 6 litres of diesel in the tank and we
brimmed it with petrol. He rounded the bill up from 38.50 of whatever his currency was to 40, the bastard.
Whatever, we'd had enough of his shit so just paid and left.</p>
<p>The car ran perfectly fine all day, as expected.</p>
<p>The next day, in Azerbaijan, shortly after filling up with 80 octane fuel (the lowest we'd encountered) the
car began to misfire horribly. It got to the point where we were coasting several seconds at a time between the
car firing. We finally found a petrol station and brimmed it with 95 octane (the best on offer) - but not before
I'd tried to siphon out the 80 octane fuel with a hose that was too short and made a royal clown out of myself
in front of 7 or 8 Azeri petrol station workers.</p>
<p>After filling up with 95 octane, the car ran fine again. For about half a mile, before the problem returned. We
had become quite concerned (although even at the time it was mildly amusing) and didn't know what to do. We pulled
over and examined the fuel filter and it was extremely blackened - presumably clogged with diesel. Aha! Good
thing we packed spare fuel filters. We fitted a new fuel filter, set off on our merry way, and the car ran fine
from then onwards.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/georgian-diesel-incident.html</link>
   <guid>http://incoherency.co.uk/blog/stories/georgian-diesel-incident.html</guid>
   <pubDate>Mon, 17 Nov 2014 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Counter creator</title>
   <description><![CDATA[A while ago Feroz created an online counter for the number
of times I've said something that could be considered racist.
The idea is that whenever I put my foot in it, somebody clicks
the button and the count increases.]]></description>
   <content:encoded><![CDATA[<p>A while ago Feroz created an online counter for the number
of times I've said something that could be considered racist.
The idea is that whenever I put my foot in it, somebody clicks
the button and the count increases.</p>
<p>This turned out to be a source of great amusement and we've since wanted to
create counters for other things. We've talked about a "productised
racism counter" for a while, but never got around to it.</p>
<p>Well I finally got around to it: <a href="http://counter.jes.xxx/">counter.jes.xxx</a></p>
<p>You can create a counter with arbitrary name and button text, and optionally a
memorable URL, to be shared with anyone.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/counter.html</link>
   <guid>http://incoherency.co.uk/blog/stories/counter.html</guid>
   <pubDate>Sun, 16 Nov 2014 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I made a brass box</title>
   <description><![CDATA[At the weekend I decided to use up the brass sheet I had lying around and construct a box.]]></description>
   <content:encoded><![CDATA[<p>At the weekend I decided to use up the brass sheet I had lying around and construct a box.</p>
<p><img width="500px" src="http://img.incoherency.co.uk/858"></p>
<p>I bought a brass door hinge to use for the hinge, and cut the box material out of my sheet of brass. I
soldered the box together using a blowtorch.</p>
<p>The main problems I had centred around a difficulty with soldering together a part of the box without
melting other parts of the box. This is the reason that the edges are so poorly aligned - I got the
first join nice and square but subsequently melted it and resoldered it several times. I eventually
developed a technique of placing large metal objects against the brass to act as heatsinks. I also
managed
to solder the lid shut right at the end, although this was easily fixed. I also ended up with lots of
stray solder running down the inside of the box due to gravity - a little more thought in the
orientation of the parts I was soldering could have prevented this.</p>
<p>After soldering it all, I cleaned up the surfaces with wet-and-dry paper to restore the surface,
which had been discoloured and blackened by the blowtorch.</p>
<p>My box is pretty shit, but I'm quite pleased that I got it to work at all after seeing how much
trouble I had keeping it together.</p>
<p><img width="500px" src="http://img.incoherency.co.uk/860"></p>
<p>If I were to make another box I would use thicker brass so that it conducts heat more
slowly, and I would bend
rather than solder wherever possible so as to reduce the amount of soldering required. I would also
have a greater awareness of heat transfer and of how the solder will flow.</p>
<p><b>Update 2014-11-17:</b> At the weekend I made another box, this one out of copper but the principle
is the same.</p>
<p><img width="500px" src="http://img.incoherency.co.uk/870"></p>
<p>The body of this box is formed out of one continuous sheet of copper which is bent up at the ends and sides,
and the rest is constructed as before. This is a far superior way to make the box. As you can see, the edges
line up much more neatly. In fact, the lid fits so neatly I had to add a little tag to make it easier to open.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/brass-box.html</link>
   <guid>http://incoherency.co.uk/blog/stories/brass-box.html</guid>
   <pubDate>Thu, 06 Nov 2014 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I ran out of fuel in my van</title>
   <description><![CDATA[Yesterday, on my way into work, I glanced at my fuel gauge and noticed that
it was extremely low. Thinking to myself, "wow! I've never seen it that low before", I made
a mental note to fill up on the way home.]]></description>
   <content:encoded><![CDATA[<p>Yesterday, on my way into work, I glanced at my fuel gauge and noticed that
it was extremely low. Thinking to myself, "wow! I've never seen it that low before", I made
a mental note to fill up on the way home.</p>
<p>My afternoon at work went badly and I didn't finish until 7. Oh, well. Anyway I got into my van
and had barely driven 50 yards up the hill before it spluttered to a halt. I knew immediately
what had gone wrong. I got out and pushed the van around so that it was pointing down the hill,
and coasted all the way down Lansdown Road and down on to London Road.</p>
<p>To set the scene: London Road is quite busy, with plenty of traffic lights and pedestrian crossings,
and to make things worse it was Halloween yesterday so there were lots of people around to laugh
at me.</p>
<p>To get from the end of London Road to the petrol station, I was scooting my van along with
one leg out of the door. I felt a bit like Fred Flintstone. I tried to steer close to the
kerb so that other people could get past me but only two cars went for it, the rest chose to
sit behind either because they were scared of me or just to laugh.</p>
<p>Anyway I scooted all the way to the petrol station, filled up, and drove home. The whole affair
probably only added about half an hour to my drive home and was pretty funny so I'm not too
bothered. Bit annoyed though as I've never ran out of fuel before.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/out-of-fuel.html</link>
   <guid>http://incoherency.co.uk/blog/stories/out-of-fuel.html</guid>
   <pubDate>Sat, 01 Nov 2014 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>I helped a French child fix a stolen moped</title>
   <description><![CDATA[While Feroz and I were driving my van around France, we came across a child
with a moped at the side of the road in some woods. He appeared to have
broken down and we decided to help him.
We pulled over and asked if he spoke English. He did not.]]></description>
   <content:encoded><![CDATA[<p>While Feroz and I were driving my van around France, we came across a child
with a moped at the side of the road in some woods. He appeared to have
broken down and we decided to help him.
We pulled over and asked if he spoke English. He did not.</p>
<p>A casual glance at his moped revealed that most of the indicators were hanging off and
the rear brake wasn't even connected. We suspect the moped was stolen.</p>
<p>Communication was getting nowhere, so I retrieved my toolbox from my van and presented
it to him. The child rummaged around and located the spanner he needed, applied the spanner
briefly to his moped, returned it and thanked us. He then removed a small nail from his
pocket, poked it through the clutch of his moped, bump-started the moped and rode off.</p>
<p>We caught up with him quickly and overtook him.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/stolen-moped.html</link>
   <guid>http://incoherency.co.uk/blog/stories/stolen-moped.html</guid>
   <pubDate>Thu, 16 Oct 2014 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>West Country Place Name Generator</title>
   <description><![CDATA[I've recently written a West Country Place Name Generator.]]></description>
   <content:encoded><![CDATA[<p>I've recently written a <a href="http://jes.xxx/westcountry/">West Country Place Name Generator</a>.</p>
<p>It has a list of words for the first half of a place name, and another list for the second half,
and combines them to make place names.</p>
<p>For example, "Compton Dando" is a real place, as is "Limpley Stoke". From these, we can generate
Compton Stoke and Limpley Dando (as well as the original inputs).</p>
<p>The page chooses a random name for the first half and a random name for the second half, and shows
the combined name. It's all in Javascript in the page source.</p>
<p>On top of this, there is a selection of free-to-use images that are used for the background picture,
as if to give a photograph of the place being named. For each name, an image is selected at random.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/west-country-place-name-generator.html</link>
   <guid>http://incoherency.co.uk/blog/stories/west-country-place-name-generator.html</guid>
   <pubDate>Fri, 18 Jul 2014 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Yurt Lush Live Tracking</title>
   <description><![CDATA[In about 3 weeks' time I'm setting off on the Mongol Rally as one half of team Yurt Lush.]]></description>
   <content:encoded><![CDATA[<p>In about 3 weeks' time I'm setting off on the <a href="http://www.theadventurists.com/mongol-rally/">Mongol Rally</a> as one half of team <a href="http://yurtlush.co.uk/">Yurt Lush</a>.</p>
<p>My boss Mike has paid for a satellite phone for us so that we can contact people if we get into trouble.</p>
<p>The phone I bought at first had the capability to send periodic location updates to some third-party
online services, however the supplier turned out to be out of stock and sent a refund.</p>
<p>I then bought an <a href="http://www.iridium.com/products/Iridium9555SatellitePhone.aspx">Iridium 9555</a>.</p>
<p>In order to do online location tracking, I've made a small system consisting of:</p>
<p><ul>
<li>Online map viewer</li>
<li>HTTP interface for posting new coordinates</li>
<li>SMS interface for posting new coordinates</li>
<li>Android app to send SMS updates</li>
</ul></p>
<p>The online map viewer is at <a href="http://jes.xxx/lush/">http://jes.xxx/lush/</a>. It loads
the coordinates from a JSON file.</p>
<p>The HTTP interface takes a latitude, longitude and message and adds an entry to the JSON data.</p>
<p>The SMS interface works similarly, and uses a number bought for &euro;0.50/mo from <a href="https://www.nexmo.com/">Nexmo</a>.</p>
<p>The Android app is a simpler method of sending the SMS: instead of opening the SMS app and inputting
coordinates copied from a GPS app, there is simply a button labelled "Send coordinates" which
gets the current location from GPS and opens the SMS app with a message already filled in, and
sending to the correct number.</p>
<p>This means we are able to send location updates via a wifi internet connection, a mobile
internet connection, satellite internet connection, mobile SMS or satellite SMS. This should give
us the ability to send location updates at any time of day or night.</p>
<p>I plan to add to the map viewer a list of recent times/messages down one side of the page, and
make the HTTP interface for new coordinates use the HTML5 location API, and add a method to
subscribe for (either instant or daily) location updates via email and/or SMS.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/yurt-lush-coordinates.html</link>
   <guid>http://incoherency.co.uk/blog/stories/yurt-lush-coordinates.html</guid>
   <pubDate>Sun, 29 Jun 2014 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Hungman</title>
   <description><![CDATA[I've made a hangman solver, currently called Hungman. The
user interface is bad but most of the idea is there.]]></description>
   <content:encoded><![CDATA[<p>I've made a hangman solver, currently called <a href="http://jes.xxx/hungman/">Hungman</a>. The
user interface is bad but most of the idea is there.</p>
<p>The bulk of it is the same as any hangman solver: take a bunch of letters and fit these to the
dictionary. This part is uninteresting.</p>
<p>The interesting part is the statistical solver. Above the dictionary-based part is a comma-separated
list of letters. These are ordered by how likely the letter is to occur in the word. There is an
<a href="http://jes.xxx/hungman/markov-model.js">order-1 Markov Model of the dictionary</a> (which will,
eventually, be a model of some text corpus so that word frequencies are taken into consideration). Using
this Markov Model, we can know, given some known letters, the probabilities of other letters following
those letters. Currently the maths in the solver is suspect but I am working on this, and it works
well enough as it is anyway. As far as I'm aware, this is the only hangman solver available that does
anything more than grepping a dictionary.</p>
<p>I plan to make this the Best Hangman Solver In The World. All that is left is a decent user interface and
non-questionable maths. Exciting times ahead.</p>
<p><b>Update:</b> this is now mathematically-grounded and uses an order-2 Markov Model.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/hungman.html</link>
   <guid>http://incoherency.co.uk/blog/stories/hungman.html</guid>
   <pubDate>Wed, 11 Dec 2013 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>NFC Tag</title>
   <description><![CDATA[Idea: NFC tag game. Whenever possible, bump your phone at someone else's to
make them "it". Then they have to do it, and periodically there is some sort
of punishment for the person who is "it". Like it vibrates to pretend there's
a text message.]]></description>
   <content:encoded><![CDATA[<p>Idea: NFC tag game. Whenever possible, bump your phone at someone else's to
make them "it". Then they have to do it, and periodically there is some sort
of punishment for the person who is "it". Like it vibrates to pretend there's
a text message.</p>
<p>Also needs to be some way to punish them if they refuse to play.
I don't want to brick people's phones.</p>
<p>I also think it would have to let you make private games. One game for all of the users could get tiresome. I will look into the technical feasibility of this; it could be fun.</p>
<p>If it's private games, you could just have a game admin and if someone is refusing to play he can just boot them, and then a random person gets made "it".</p>
<p>Soliciting ideas for a name...</p>
<p>I will blog about my plan (although <a href="https://incoherency.co.uk/blog/stories/polynomial-interpolator.html">last time that happened</a> I didn't actually implement it, so perhaps I shouldn't).</p>
<p>Idea from <a href="http://www.reddit.com/r/AskReddit/comments/1nu69i/if_you_were_an_all_powerful_dictator_what_trivial/ccm4yx1">here</a>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/nfc-tag.html</link>
   <guid>http://incoherency.co.uk/blog/stories/nfc-tag.html</guid>
   <pubDate>Sun, 06 Oct 2013 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Beer</title>
   <description><![CDATA[I've been brewing some more beer recently.]]></description>
   <content:encoded><![CDATA[<p>I've been brewing some more beer recently.</p>
<p>Will and I used to talk about opening a brewery, but it'll probably never happen. Pipe dream.</p>
<p>The beer is brewed from a two-tin kit (i.e. two tins of malt extract rather than the more common
one tin of malt extract plus a shitload of sugar) and the kit also includes "hop powder", which is
this mysterious powder which smells like hops.</p>
<p>This is the beer in the process of being barreled.</p>
<p><img width="500px" src="http://img.incoherency.co.uk/696"></p>
<p>This is the beer in the barrel.</p>
<p><img width="500px" src="http://img.incoherency.co.uk/699"></p>
<p>This is the first pint I poured.</p>
<p><img width="500px" src="http://img.incoherency.co.uk/705"></p>
<p>The beer has only been in the barrel for a day, and is not ready for drinking.</p>
<p>The beer is good, for homebrew.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/beer.html</link>
   <guid>http://incoherency.co.uk/blog/stories/beer.html</guid>
   <pubDate>Mon, 23 Sep 2013 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Xory</title>
   <description><![CDATA[My latest project: Xory. I started this on Friday afternoon
and now consider it releasable.]]></description>
   <content:encoded><![CDATA[<p>My latest project: <a href="http://xory.pm/">Xory</a>. I started this on Friday afternoon
and now consider it releasable.</p>
<p>It's a picture guessing game inspired by <a href="http://individual.utoronto.ca/somody/quiz.html">Prof
or Hobo</a> where you're shown a series of images and have to guess between two categories.</p>
<p>It's under 500 lines of Perl, and uses Mojolicious for the app framework and Bootstrap 3 for the UI.
Bootstrap 3 is in some ways a regression in my opinion. The fresh look is nice, and having it responsive
by default is also nice, but having to compile it is needless hassle. Mojolicious, as always, was a joy to work with.</p>
<p>I'm a little uneasy about using DBM::Deep for the database. DBM::Deep is pretty buggy but really does make
things easy. DBM::Deep allows me to store all state in a giant hash, and not have to worry about writing to
disk. It probably does introduce difficult race conditions if running under hypnotoad or similar, but I currently use
a single-threaded server so that's not a problem. There are definitely some race conditions in Xory, caused by
handle_uploaded_pic running in fork_call, but they'll only be invoked if someone tries to upload two pictures
at once so I'm not going to worry about it for now.</p>
<p>The game is similar in concept to <a href="https://github.com/jes/guess-whom">guess-whom</a>, in that
it asks the user to create the game and is based around sets of pictures. It's a lot simpler though, to
the extent that I finished it before getting bored.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/xory.html</link>
   <guid>http://incoherency.co.uk/blog/stories/xory.html</guid>
   <pubDate>Tue, 10 Sep 2013 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Mazda MX-5</title>
   <description><![CDATA[Today I almost bought a Mazda MX-5.]]></description>
   <content:encoded><![CDATA[<p>Today I almost bought a Mazda MX-5.</p>
<p>This Mazda MX-5 in fact:</p>
<p><img src="http://img.incoherency.co.uk/665"></p>
<p>I bid &pound;507 yesterday, with about 17 hours to go.
I woke up this morning to find that I was still the winning bidder.
With an hour left to go, I was still the winning bidder.</p>
<p>At this point I got a little scared. I hadn't <i>really</i> intended
to buy the car. Had I? Plus, it had 120,000 miles on the clock, the
seller had 0 feedback and it was 250 miles away, in Lancashire.
And there were only photos of one side of the car.</p>
<p>In the end somebody outbid me and the winning bid was &pound;517 so
everything was fine.</p>
<p>I think that'll be the end of my phase of bidding on MX-5's that I don't
really want to buy.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/mx5.html</link>
   <guid>http://incoherency.co.uk/blog/stories/mx5.html</guid>
   <pubDate>Wed, 28 Aug 2013 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>The Glowstick Debacle</title>
   <description><![CDATA[This is a story about how I tried to make some money on eBay, and ended
up losing a bunch instead.]]></description>
   <content:encoded><![CDATA[<p>This is a story about how I tried to make some money on eBay, and ended
up losing a bunch instead.</p>
<p>I bought a package of 1000 glowsticks for &pound;30 to sell on eBay in groups of 10 for &pound;2.</p>
<p>So I listed them, and loads of people bought them. I was dead popular as I was so much cheaper
than everyone else.
Even with a good deal on stamps, after buying the stamps, the glowsticks, the envelopes,
and paying eBay and PayPal fees, I was only making something like 12p per sale.</p>
<p>Anyway, I sent out a bunch of glowsticks, but everyone started complaining that
they had been set off in the post and therefore did not work. I refunded everyone's money, and started putting
thick cardboard in the envelopes to stop them from bending.</p>
<p>Then everyone complained that, when it arrived, they had to pay the postman for
the envelope as it was too heavy for a single 2nd class stamp.</p>
<p>In the end, I annoyed a lot of people and had to give every single customer a refund.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/glowstick-debacle.html</link>
   <guid>http://incoherency.co.uk/blog/stories/glowstick-debacle.html</guid>
   <pubDate>Thu, 15 Aug 2013 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>8 out of 10 Countdown viewers</title>
   <description><![CDATA[I added more fine-grained analytics to my Countdown Solver recently,
and I noticed something interesting today.
Here are the most-solved letter sets from Friday (note the last three):]]></description>
   <content:encoded><![CDATA[<p>I added more fine-grained analytics to my <a href="http://incoherency.co.uk/countdown/">Countdown Solver</a> recently,
and I noticed something interesting today.
Here are the most-solved letter sets from Friday (note the last three):</p>
<p><img src="http://img.incoherency.co.uk/642"></p>
<p>And here's a chart which is relevant:</p>
<p><img src="http://img.incoherency.co.uk/644"></p>
<p>I have figured out what is going on.</p>
<p>Countdown is on every weekday.
But if you look at the chart,
there are clear spikes every Friday and Monday, for the last 3 weeks.
(Except this coming Monday hasn't happened yet).</p>
<p>Do you know "8 out of 10 Cats"?
It is a comedy show with Jimmy Carr.
There is a special type, shown on Fridays at the moment, called "8 out of 10 Cats Does Countdown."
The show is repeated on Mondays.
I get a huge spike in users on these days, as so many more people watch it than regular Countdown.</p>
<p>The top 3 letter sets are normal sets that come up in the game.
9 letters, same as in regular Countdown.
<tt>nosefart</tt> and <tt>lastanus</tt> are the sort of crude teatime teasers used on the 8 out of 10 cats version.
And they're 8 letters, which is consistent with teatime teaser.
And <tt>acleanbum</tt> is the conundrum.</p>
<p>So the conclusion we can draw,
by looking at the table of most-solved letter sets,
is that there are around 200 people
who sit and watch "8 out of 10 Cats Does Countdown"
and ruin it for themselves :p.</p>
<p>And in case you're wondering:
<tt>nosefart</tt>/<tt>seafront</tt>,
<tt>lastanus</tt>/<tt>sultanas</tt> and
<tt>acleanbum</tt>/<tt>ambulance</tt>.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/8-out-of-10-countdown-viewers.html</link>
   <guid>http://incoherency.co.uk/blog/stories/8-out-of-10-countdown-viewers.html</guid>
   <pubDate>Sun, 11 Aug 2013 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Polynomial interpolator</title>
   <description><![CDATA[Here's what the web needs: a simple-to-use polynomial interpolation tool.  ]]></description>
   <content:encoded><![CDATA[<p>Here's what the web needs: a simple-to-use polynomial interpolation tool.  </p>
<p>I am going to make one this weekend as I can't find one.
However, I'm trying to do polynomial interpolation on paper and am getting it wrong.</p>
<p>(Which, if anything, just proves how much a tool is needed).
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/polynomial-interpolator.html</link>
   <guid>http://incoherency.co.uk/blog/stories/polynomial-interpolator.html</guid>
   <pubDate>Sat, 10 Aug 2013 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Phone posting setback</title>
   <description><![CDATA[Yet another setback in the phone posting project.]]></description>
   <content:encoded><![CDATA[<p>Yet another setback in the phone posting project.</p>
<p>The aerials I have are not the same connector as the connector on the phone :(.</p>
<p>Joe called it.
</p>]]></content:encoded>
   <link>https://incoherency.co.uk/blog/stories/phone-posting-setback.html</link>
   <guid>http://incoherency.co.uk/blog/stories/phone-posting-setback.html</guid>
   <pubDate>Thu, 08 Aug 2013 12:00:00 GMT</pubDate>
  </item>
 </channel>
</rss>
