In 2022 I started to design a new hardware system for our interactive sculptures, which are typically room-filling constructions of metal, plastic, and glass hand made from thousands of custom made components. The sculptures have embedded electronics that create a dynamic and interactive behaviour with sensor inputs (IR, captouch, microphones) and actuator outputs (lights, vibrating fronds, curling shape memory alloy arms). Actuators and sensors are controlled by embedded microcontrollers that connect to a network to receive and publish information.
The legacy hardware system was expensive, cumbersome, and unreliable. I wanted to design a new system that would: allow us to design and produce projects faster, be more robust during installation, take advantage of our growing software toolkit, and better align with our research goals.
Goals
The project was a development from the concept design I started in 2021, but with these updated design goals:
- a more modular topology
- i.e. a simple, shallow system topology that is easy to scale into larger or smaller projects, and easy to pre-install as sub-assemblies before shipping projects internationally
- lower cost per actuator, including design/production/testing/installation time
- flexible supply chain, design for availability
- i.e. not reliant on parts that are irreplaceable if there is a component shortage
- protection against common installation errors
- i.e. can be handled and installed reliably by laypeople, which is necessary for remote installations
Design
Modular System Topology
The legacy system’s topology was unnecessarily complex, and it made everything from planning to production to installation difficult and expensive. Here’s the general structure:
This system had a lot of layers, a lot of different boards and cables, and fit together in a very hierarchical control scheme, which was not aligned with our goal of making distributed systems where we could start to create emergent behaviour. In contrast, the new system is very shallow and lends itself well to distributed control schemes:
In the new system, the high-current switching and sensor signal filtering are integrated into the controller PCB. The new microcontroller (ESP32) is also able to directly connect to the wireless network, making the Raspberry Pi unnecessary. Messaging on an IP network is also much easier to monitor than UART messages between boards.
Also, the new system uses 24V power rather than the legacy system’s 12V. This reduces the impact of voltage drop between the off-stage power supplies and the sculpture, and allows more devices to be powered by a single supply cable. Cable management seems to feel exponentially more difficult with more cables (the bundles get bigger, heavier, less flexible), so this has a surprisingly big effect on production and installation time.
Here are system drawings I made for two projects: the legacy system in Meander (left), and the new system in Poietic Veil (right). While you won’t know exactly what the symbols mean, I think it is clear that the system on the is simpler.
- 165 actuators
- 4 types of PCB
- 68 total PCBs
- 7 power cables from the power supplies to the sculpture
- 7 Ethernet cables for wired communication between a central computer and the sculpture PCBs
- 172 actuators
- 1 type of PCB
- 40 total PCBs
- 3 power cables from the power supplies to the sculpture
- Wireless communication between the computer and sculpture PCBs
Since the new controller boards only need a power connection, they are easy to pre-install in sub-assemblies that could be built and tested entirely on the ground and popped into the sculpture. That helps with partially decoupling electronics installation from the critical path.
The smaller modular clusters of electronics also make for a system where failed hardware is less impactful. If one board in Poietic Veil (new system), only 4 actuators would be inactive. In Meander (old system), one failed Raspberry Pi could take out 36 actuators. Repair / replacement of hardware in the new system is also much easier with a single PCB in a small, removable sub-assembly.
We also use our sculpture electronics in STEAM (STEM + Art) kits, so having a single board to control a small group of actuators and sensors is much easier and cheaper to produce, and much easier to understand for students. Our legacy system was so complex and expensive that it was next to impossible to use effectively in student kits. Instead we were using breadboard setups, which were error-prone and less effective as a teaching tool for our purposes.
Design for Availability
During the covid-related supply chain instability, it was impossible to get the microcontrollers we were dependent on for our legacy hardware. That was a driving factor in making the jump to new hardware, and I didn’t want to be exposed to the same vulnerabilities. I also knew that I wouldn’t be at this company forever, and I wanted to leave a system that wouldn’t require a redesign. Most of the parts I chose are fairly generic, and all of them have a drop-in replacement available at least from the same manufacturer, if not from other manufacturers. The only particularly unique part would be the microcontroller, so I decided to design around a footprint/pinout standard for discrete microcontroller boards from Adafruit, their Feather system. The Feather system standardizes the pinout and I/O requirements for a number of microcontrollers, meaning there were several drop in replacements. Also, Adafruit produces a wide range of off-the-shelf modular expansion boards which could be useful for future projects with no extra hardware design.
In 2024 I did a minor revision to the design to make the board much cheaper by embedding the microcontroller module directly onto the controller PCB. I kept the Feather headers with the correct pinout though, in case the ESP module is out of stock, in which case the discrete Feather could be used instead. The ESP module is only $5 though compared to the Feather’s $30, so it is obviously preferable to use the module when possible.
Protection Against Installation Errors
Affectionately known as idiot-proofing, the goal here is to prevent someone from accidentally frying hardware during testing or installation. Because of the scale of our installations, we always had to hire local assistants to help us produce and assemble sculptures. This meant that plenty of non-engineering team members made cables and hooked up sub-assemblies. Even with thorough quality control we would still get fried boards in our legacy system due to a design flaw that was hard to track down.
There were a couple of potential vulnerabilities that I wanted to eliminate by design with the new system:
- Prevent someone plugging a power cable into the wrong port
- Prevent damage from incorrect polarity on a power cable or power supply
- Prevent damage from multiple supplies being connected simultaneously
I made it impossible to plug the power cable into the wrong port just by using a different port size. I really wanted to use this connector series from Phoenix which was small, keyed, and crimp-less, making assembly and installation easy. But since both the actuators and power input were 2-conductor cables I chose to use the 4 position connector for the power cable, which then wouldn’t fit into an actuator or sensor port.
I also prevented damage from a reversed polarity cable by using a bridge rectifier on the input, since we made all our own cables, often with help from assistants.
Lastly, I needed to protect the boards and upstream equipment from being being damaged from multiple potential power sources. Especially during testing, we may have a 24V DC power supply connected to the main power input port, as well as a USB cable connected to either the USB port on the controller board itself or the discrete Feather board, depending on how we configured the board.
The possible sources of power that could all be connected simultaneously are: a 24V DC power supply connected to the main power input port, a USB cable into the on-board USB port, and a USB cable into the discrete Feather board.
I needed either the USB cable or on-board 5V buck regulator to be able to power the actuators, but I had to prevent the 5V regulator from powering the upstream port, as required by the USB 2.0 specification (section 7.2). A schottky diode easily provides this protection.
I also had a 3.3V regulator on board to power the microcontroller from the 24V supply, but if a discrete Feather board was used, it also had its own 3.3V regulator that would be powered from the USB supply, with their outputs on the same net. In order to prevent any potential damage from small differences in their outputs, I disconnected them with a PMOS transistor if a USB cable was plugged in:
At an early stage of the design I was also considering using a physical lockout to connect the VBUS net to the 5V net with a tall jumper that blocked the USB port, so that you couldn’t accidentally plug the USB cable in while the nets were connected. I didn’t end up doing this but I still think the idea is pretty fun:
Component Selection and Schematic Capture
Microcontroller Module and Feather Headers
This section has the ESP32-S3 microcontroller module, decoupling caps, a general purpose indicator LED, reset and bootloader buttons, the standard Feather header pinout, and an extra header row to pass regulated 5V power to stacked expansion boards. The one challenge with the header pins is that the ESP32, ESP32-S2, and ESP32-S3 all have an issue where they can’t use one of their ADC peripherals while using WiFi, and the pins connected to the usable ADC are not the same for all of Adafruit’s Feather boards. Since the base board here only needed one analog input pin, I picked one that was on the usable ADC for both the ESP32 and ESP32-S3.
I mentioned a stacked expansion board, which I designed to add an additional 6 actuators in the same small footprint:
5V Supply
Our actuators (LEDs, vibrating fronds, shape-memory-alloy arms) use 5V power, and draw 100mA to 2A each. Normally we only have a couple of 100mA-500mA actuators connected, and we control them with PWM so their RMS current is fairly low (<1A). But, there are situations where we can have 3 high-power actuators (2A each), so I needed to still allow for >6A at max load. That meant we would be operating the regulator at a much lower efficiency most of the time, but this was not a primary concern for us.
I picked a buck regulator that is capable of up to 12A of continuous power in a tiny 24-QFN package, that costs just $2. It is also pin-compatible with 7 other drop-in replacement parts that can output 8-12A, which will make it much more likely that we wouldn’t have supply chain issues.
This component doesn’t have a SPICE model to simulate with but the manufacturer provided an excel design calculator to help determine component sizes. I chose to target a 400kHz switching frequency and a current ripple of 30-50% as per the datasheet’s recommendation. I probably could have gone with a higher switching frequency e.g. 600kHz to make the components smaller since efficiency wasn’t a big concern for this application, but I didn’t have much trouble fitting in the larger components for 400kHz anyways.
I followed the design calculator’s recommendations for peripheral component sizing, with the exception of the input caps. The Cin recommendation was ~30uF effective capacitance, but reasonably sized caps that I could find had a 60-80% DC bias de-rating at 24V so I would have had to use a lot of big caps to make that work. I got in touch with the manufacturer and got them to send me an evaluation board, and I noticed that they only had 16uF effective Cin. So I chose to use similar values, and the board worked out fine.
One issue I didn’t realize when I first designed this board was that the light-load features on many switching regulators will cause the switching frequency to drop. Since we have this unusual application where the peak current could be >6A but the average current is <1A, we normally operate in the light-load region, and if the load is very light (e.g. <0.1A), then the switching frequency drops into the audible range and makes a horrible whining noise in the inductor (due to the Lorentz force).
When this happened on my early prototypes I had no idea what was causing it, and I initially suspected it was due to the MLCC input caps because of this article I read.
But when I put my scope on the output in a lightly loaded condition, I saw that the output ripple was around 4kHz, easily in the audible spectrum.
There is one pin-compatible part that has a forced PWM mode rather than the PFM mode that the other 7 parts use, but I didn’t want to make this design dependent on a single part. I also found other parts that e.g. have a forced continuous conduction mode (FCCM) which would similarly resolve the issue, but those parts seemed less common and more expensive, so I couldn’t justify them for this board. So to resolve the noise issue, I just added a dummy load resistor between 5V and GND to keep the output load at least above ~0.1A while the regulator is on. It wastes some power but that is much less important than making an irritating whine.
3.3V Power Supply
The microcontroller uses 3.3V power, and I could either use a buck converter with the 12-24V input, or use a low drop out (LDO) regulator to step down the available 5V DC from the actuator buck converter. A dedicated buck converter would be the most efficient, especially because the ESP32 family of microcontrollers are very power hungry. Also, because a 3.3V buck would be independently supplied from the source, we would be able to turn the 5V regulator off when we didn’t need it. But a buck regulator with peripherals is much bigger and more expensive than an LDO. We weren’t very concerned with efficiency on this board (we are always connected to a wall supply), and it was actually preferable to free up a GPIO pin by not dedicating it to the 5V_EN pin, so I went with the LDO.
Ports
I picked Phoenix’s PTSM series of ports because they are small, keyed, and the cable headers don’t require crimping or soldering. Very conveniently they are also 0.1” pitch, identical to breadboard wires and header pins - something we took advantage of for our Classroom Kits. I used the 4 pin variant for the power input so that a power cable couldn’t accidentally be plugged into a sensor or actuator port.
Our sculptures commonly use hexagonal structures, hence the 6 actuator ports and stackable +6 actuator ports in the expansion board.
Sensor Ports
We typically used analog IR sensors for our sculptures, and since adopting the ESP32 microcontroller, we started using its capacitive touch sensing pins too. The captouch pin can be directly connected to an antenna, like we used in Poietic Veil.
For the analog signal from the IR sensor, I had to step the voltage down to 3.3V for the microcontroller, and I passed it through a buffer for extra protection. I also added a low pass filter to smooth out the sensor signal for the human-scale interaction that we see in our sculptures. I also added a filter disconnect jumper, and additional slots for modifying the cutoff frequency in case that is ever needed.
Both the sensor and op-amp have decoupling capacitors to help filter out high frequency noise from switching and digital signals in the rest of the board. I considered using Pi filters to really eliminate high frequency content, but we didn’t need extremely accurate sensor readings so it seemed unnecessary here.
Actuator Switching
The actuator ports use an N-channel mosfet switch to power the actuators, with an indicator LED in parallel.
Layout
My goal with this board was to make it as small as possible with single-sided assembly. My constraints were:
- use the Feather standard spacing for the header pin rows
- place all actuator and sensor ports on one edge (an agreement with the architecture team)
- follow guidelines as closely as possible for components that are layout-sensitive (the microcontroller’s antenna and the switching power supplies)
Stackup, Signal Integrity, and EMI
I chose to use a 4 layer stackup with two internal ground planes (S/P-G-G-S/P) for a couple of reasons:
- Since we fab with JLCPCB, 4 layer is about the same price as 2 layer, but there is a significant jump to 6.
- I wanted two ground planes so that both the signal layers were very close reference plane.
- By having both reference planes at the same voltage I can use return vias between them for when my signals change layers, minimizing how much noise they propagate through the rest of the board.
- Having a copper plane on each side of the core helps with copper balance to reduce any warping.
- The board is fairly low density because a couple prominent features dictate the outer dimensions, so I didn’t need to use a G-S/P-S/P-G stackup to give me more routing space.
With this stackup, signal traces are only about 0.2mm away from a reference plane, which helps with minimizing inductance and noise transmission to other lines. Wherever possible I also tried to follow the “3H” principle for trace spacing, and when traces do come closer than that I make sure to keep that section as short as possible. I know that’s just a rough rule of thumb but I figured that since most of my signals were DC power, low frequency digital, and digital PWM, I didn’t need to worry more than that because signal integrity doesn’t really matter in those cases. Even for USB I figured it wouldn’t be that important because it is a fairly tolerant protocol, and in this case it would almost exclusively be used just for program upload when everything else is inactive.
I initially thought that I might use L3 for an extra signal+power layer, but after doing some research I found that it is much more desirable to have ground as my reference plane for my other two signal layers. This lets me use ground vias to create a short return path when my signals switch layers, greatly reducing how much EMI propagates through the rest of the board. So again in this case, even though I probably didn’t need to, I put a ground via next to every signal via. For good measure, I put 4 vias next to the switching regulator feedback via since those are probably the most sensitive nets on this board.
I haven’t worked on boards where EMI and signal integrity is critical, but I always want to design boards with best practice in mind where possible.
Regulator Layout
The feather headers, mounting notches, and actuator+sensor connectors essentially dictate the minimum board outline dimensions. With those placed, I prioritized placing the 5V regulator since switching regulators can be sensitive to poor layout.
For this layout I tried to follow good practice according to application notes such as these:
- I kept the switching node and high frequency loop areas small to minimize any potential issues with EMI.
- I made the feedback trace thin, and routed it on a short path that avoided the switching node, starting from a stable point next to the output capacitors.
- I made sure to connect signal ground to the ground plane with a single via to keep the small signal components from picking up noise.
Other Layout Notes
Some other guidelines I tried to follow as best as possible were for the clearance around the ESP32 module’s antenna, and the USB bus differential impedance. For the antenna, Espressif’s design guide recommends putting it on the board edge and giving it a cutout or at least a copper clearance area, with recommended clearance dimensions. I couldn’t quite meet the minimum FR4 cutout dimension on one side because of the mounting notch, but I have made other boards with this module with just a copper keep out area and no FR4 cutout so I know it will work well enough.
For the USB bus, while this port is pretty much only used for program upload where the bus speed is < 1MHz, I figured I would route the data pins as a proper differential pair and add an ESD protection chip as well for good measure. Digikey has a great guide that I followed, with these values for my differential pair traces and the standard 4 layer JLC stackup. The length of each trace was less than 0.3mm so I didn’t need to do additional length matching.
Finally, I’ll also point out we decided to use notches for mounting this board with snap-fit joints to reduce the number of parts in the assembly.
Assembly Jigs
The first version of this board was used in Poietic Veil, and I didn’t order them with through-hole components assembled, so I made some jigs to make that process quick. JLC now assembles through-hole components too so there isn’t a need for these, but they were satisfying.
Software Topology and Research Goals
This project helped us take a big leap forward in our pursuit of highly distributed systems. PBSI builds systems containing hundreds of actuators and sensors, but the long term goal is to work towards systems that contain thousands. One of the biggest bottlenecks to that theoretically (i.e. other than the cost of building these huge systems) was scalability. The software we started developing in 2018, Testbed Control, was a huge step forward from its predecessor, but it used a centralized control system where most of the processing happens on an off-stage computer. The computer creates different behaviours and calculates their superimposed influence on every device in the sculpture before passing on that info to those devices. So with bigger systems naturally requiring more calculations, and computation being focused in a single behaviour composer, we would need to use bigger more expensive computers. Even if we wanted to add new tools capabilities to an existing sculpture we would have to replace the original computer.
Our new hardware system, in contrast, makes it far easier for the distributed boards to perform their own calculations. In Poietic Veil, we adapted the lightweight SAI-based control system of Reef to run on the new hardware. We moved the the behaviour computation onto the microcontrollers, and set up a system where updates and configuration settings would be passed wirelessly through MQTT and OSC messages.
The microcontrollers took on most of the work of calculating their response to shared spatialized behaviours, making the system inherently more scalable. A bigger system with more controllers will automatically have more processing power.
More than just scalability though, this is also a huge step for our design philosophy. This gave us the ability to create decentralized systems where devices are generating their own behaviour based on shared information. Without needing a constant flow of high-bandwidth information, we are able to produce large gestures of coordinated, emergent behaviour.
Appendix: Eagle
In case you are searching for where I’ve used Eagle in this project, the version before the current iteration was made in Eagle. For the latest iteration, I wanted to move to a 4 layer board for a cleaner and better layout, but the free Eagle license doesn’t support that - so I moved it to KiCad. My general knowledge of good layout practices is also better, so this version looks worse.
The layout I used for this original design obviously has a lot of issues:
- it’s a 2 layer stackup with broken return paths for many of the traces.
- the regulator’s analog components are very spread out, and the high frequency loop from Vin through Vout is way bigger than it needs to be.
- the regulator’s feedback trace is wide and very long.
- there are some through-hole test points on sensitive lines (feedback, Ton) that probably don’t help with the regulator’s stability.