The Arduino platform has a lot of advantages. It’s designed so that artists and hobbyists can do lots of cool stuff. There are plenty of tutorials for beginners, and the standard hardware means that incompatibilities won’t add extra confusion when learning microcontroller programming. Getting started is inexpensive — for $25ish, one can get a relatively self-contained hardware prototyping platform. Also, Arduino was carefully designed to have a smooth transition to more specific hardware in production — the hardware is open, and there isn’t any vendor lock-in.
However, there are also many benefits to reaching beyond Arduino. Much useful hardware isn’t available in a “shield“ package (and what is tends to be expensive compared to just the components), and changing the hardware allows more flexibility in price, power, and size. Also, using C and its tools allows more options than the Arduino environment alone. (And it’s fun to learn how things work at a deeper level!)
Unfortunately, once you try to move a step or two outside of the Arduino ecosystem, beginner-friendly documentation gets thinner. The information is there if you know how to find it, but many questions have to be answered at once, upfront.
I have been using “raw” AVR microcontrollers for some personal projects, and I’m going to describe are some tools and resources I’ve found useful. (There are also non-AVR microcontrollers, like PICs, but I’m going to ignore those because they have less in common with Arduinos.) Read more on Completing the Circuit: From Arduino to AVR Microcontrollers for Hobbyist Projects…
Lua is a deceptively simple language. Its designers have done such a good job of keeping it downwardly scalable to simple uses that it’s easy to overlook the advanced parts. One of these is its polished implementation of coroutines.
Why Coroutines Matter
The combination of coroutines, tail-call optimization, and closures means that many sophisticated control structures can be implemented in Lua pretty easily. Rather than turning functions inside-out and nesting them inside an arbitrary primary function, untangling them and giving each its own main loop often simplifies things. Allowing individual closures to suspend and resume means that backtracking, lazy streams, constraint propagation networks, and so on can be expressed cleanly. Also, asynchronous IO can be coordinated with functions like
luasocket.select scheduling coroutines; each can still be read linearly, and there’s no need to CPS-transform everything by hand with callbacks.
Read more on A Field Guide to Lua Coroutines…