Introduction: A Solar-powered Embedded System for Ecological Audio Signal Processing

About: I'm a sound artist and researcher based in Graz, Austria. https://www.danielepozzi.com/

This instructable describes how to realize a solar-powered embedded system for real-time audio signal processing. Based on a Raspberry Pi Zero 2 W, the system is very portable and flexible. It features a dedicated sound card, a two channels 5W amplifier and a MEMS microphone in a 150 mm x 116 mm IP66 waterproof box. A combination of custom hardware and software makes the system energetically autonomous, waking it suitable for unsupervised outdoor installations. A low cost loudspeaker is also realized, with custom enclosure for a Dynavox Minibass PS-138. The first version of the system was originally developed for Klangnetze (2022), a collaborative sound art project for public spaces in Styria, Austria.

Supplies

Power cycling circuit components:

Raspberry Pi components:

Loudspeaker components:

Waterproof enclosure:

Step 1: About the System

This is a detailed guide to make an autonomous, solar-powered embedded system for real-time audio signal processing. The project is relatively complex, as it involves several hardware and software components that need to work altogether. This instructables describes how to realize the loudspeaker and the waterproof box containing all the electronics.

Step 2: What's in the Box

The waterproof box contains a Raspberry Pi Zero 2W, a Raspiaudio MIC+ audio shield, a boost converter, a 18650 battery and battery holder and the power cycling circuit.

Step 3: Power Cycling Logic

The power cycling circuit implements a double logic to make the Pi power on and off autonomously. This is realized by turning on and off the booster, which powers the Pi, according to sunlight conditions and battery level. In particular: booster turns on only if sun is shining and battery voltage is above 3.9V. Booster turns off either after sunset, or if battery voltage is below 3.9V. Also, booster turns off only after Pi has completed shutdown, to avoid SD card corruption.

  • !INT is the inverted INT pin of the LC709203F. This is HI when battery voltage < 3.7V, LO when above.
  • !PGOOD is the inverted PGOOD pin of the BQ24074. This is HI when sunlight hits the solar panel, LO otherwise.
  • !POWEROOF is the inverted (active_low) Pi GPIO pin 26 with poweroff overlay enabled. This pulls LO after Pi completes shutdown. It goes back HI after Pi boot.

Step 4: Positive NOR Gates

The positive NOR gates will output HI when both inputs are LO, LO in any other case (SN74HC02 datasheet). This means:

  • The first NOR outputs HI when battery is below 3.7V (INT == LO) and Pi is shutdown (!POWEROFF == LO).
  • The second NOR outputs HI when there is no sun (!PGOOD == LO) and Pi is shutdown (!POWEROFF == HI).
  • When either one of these conditions is met, the third NOR outputs LO, turning off the booster. This means the whole system powers off either after sunset, or when battery is below 3.7V (in both cases, after Pi shuts down). To turn the system back on, both !PGOOD and INT need to be HI again. This will cause the first two NOR gates to output LO, and therefore the third NOR gate to output HI, turning on the booster and passing current to the whole system.

The first thing we want to do is to automate Pi shut down according to battery and sun conditions. We therefore need to test hardware communication and write a script that shuts down Pi either when no sun is detected, or when we have low battery.

Step 5: Burn Raspi OS Image

Starting with a fresh new SD card, we first install Raspi OS. This project was built and tested on:

Raspberry Pi OS

  • Release date: September 22nd 2022
  • System: 32-bit
  • Kernel version: 5.15
  • Debian version: 11 (bullseye)

Headless setup guide

Raspberry Pi Imager is a good tool

Step 6: Test the Audio Shield

We then want to test that all the main electronics components are working and communicating properly. We start from testing sound. Insert the Rapspiaudio MIC+ Shield in the Raspberry Pi as shown in the picture, then turn it on. Detailed instructions are on the Raspiaudio website.


Once Pi has booted, open a terminal and type:

wget -O - mic.raspiaudio.com | bash

reboot, then:

wget -O - test.raspiaudio.com | bash

Push the onboard button, you should hear “Front Left” “front Right” then the recorded sequence by the microphone.

Step 7: Test I2C Communication (LC709203F ~ Pi)

In this step we test for I2C communication between the LC709203F battery monitor and the Pi. In particular, we want to be able to get the current battery voltage value from the LC709203F, and to set the INT pin on the LC709203F to go LOW at a specific threshold (here 3.9V). As shown in picture:

  • Connect board VIN (red wire) to Pi 5V
  • Connect board GND (black wire) to PiGND
  • Connect board SCL (yellow wire) to PiSCL
  • Connect board SDA (blue wire) to PiSDA
  • Plug battery into either of the JST battery ports.

Detailed instructions here. Once everything is connected, power on the Pi, then:

Install the LC709203 library.

pip3 install adafruit-circuitpython-lc709203f

Slow down the I2C clock as described here:

sudo nano /boot/config.txt

At the end of file, add:

# Clock stretching by slowing down to 10KHz
dtparam=i2c_arm=on
dtparam=i2c_arm_baudrate=10000

Test whether the LC709203 is there:

i2cdetect -y 1

You should get something like this:

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- 0b -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --       

Test battery monitor:

sudo nano battery.py

Copy and save the following code. This reads battery voltage every second and sets INT pin to go LOW at 3.9V (I2C register 0x14).

import time
import board
from adafruit_lc709203f import LC709203F

sensor = LC709203F(board.I2C())
sensor._write_word(0x14, 3900)

while True:
    print(sensor.cell_voltage)
    time.sleep(1)

Run:

python battery.py

Terminal should now print the battery voltage.

Step 8: Test Solar Charger

Here we want to test whether we can read the state of the solar charger PGOOD pin through the Raspberry Pi GPIO pin 13. The PGOOD pin indicates whether sunlight reaches the solar panel or not. Connect PGOOD to GPIO 13, as shown in picture. Then create the file sun.py:

sudo nano sun.py

Copy and save the following code:

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)

sun = 13
GPIO.setup(sun, GPIO.IN)

while True:
if GPIO.input(sun):
    print("no sun")
else:
    print("sun")
time.sleep(1)

Run:

python sun.py

Try to hover a light on the solar panel, then move it away. Terminal should print "sun" and "no sun" accordingly.

Step 9: Enable Poweroff Overlay

Enable poweroff overlay. GPIO pin 26 will go LOW at pi shutdown, will be HI after boot. This will be useful to make a graceful automatic shutdown.

sudo nano /boot/config.txt

At the end of file, add:

dtoverlay=gpio-poweroff,active_low

If all tests were successful, we can now make the power cycling circuit.

Step 10: Schematics

The power cycling logic is realized through two Quad positive NOR gates and one NE555 timer.

  • The first QuadNOR (QuadNOR1) is used as an inverter. It inverts the value of PGOOD and INT. All the inputs of the two unused gates are connected to ground.
  • The NE555 is set in monostable mode (a.k.a. single shot mode) to de-noise the value of INT at the 3.9V threshold. Specifically, when INT switches from LO to HI at 3.9V, the booster turns on, causing the Pi to boot. This sudden load causes the battery monitor to detect a voltage lower than 3.9V. The INT value therefore goes LO again. Since this happens in a fraction of a second, the Pi finds itself still in a very early boot phase - in particular, GPIO26 will still be LO. With both Pi and INT LO the booster turns off again, causing an infinite boot loop. To avoid this the NE555 IC is set in monostable mode to keep the INT value HI for at least 10 seconds, which is largely enough for the Pi GPIO pin 26 to go HI and complete the boot. The value of R1 and C1 determines how long the output of the NE555 timer will stay HI. Click here to open an online simulation.
  • QuadNOR2 performs the logic desribed in step 3.

Step 11: Prepare the Perf Board

The circuit is built on a small piece of perforated board. Take your enclosure and measure two mounting points, drill holes.

Step 12: Solder Sockets

Step 13: Solder All Caps and Power Rails

Step 14: Complete the Logic

Step 15: Solder Connectors

Step 16: Solder Pi and Booster

Step 17: Put It All Together

Insert the solar charger and battery monitor in the sockets. Connect cables to Pi SDA - SCL and to GPIO 13 - 26. Connect booster ENABLE to the power cycling circuit.

Step 18: Test

Test the power cycling circuit. Start by providing a current of 4.0V and hover a light relatively close to the solar panel. Once Pi boots, run sun.py. Move the lamp away from the solar panel and check that terminal prints "no sun". Move the lamp back on the panel and check that terminal prints "sun". Now run battery.py and check that you get correct voltage printed (~4V). Now turn down the voltage from your power supplier to a value below 3.9V, and shut down your Pi manually. Pi should shutdown, followed by booster turning off. Now turn up your power supply to exactly 3.9V. Booster should turn on and Pi should boot. Move away the lamp from the solar panel and shut down Pi manually. Pi should shutdown, followed by booster turning off.

If test succeded, the circuit is working properly. We can now mount everything in the waterproof enclosure.

Step 19: Battery Holder

Step 20: DC Plug and Power Switch

Step 21: Jack Plug

Step 22: MEMS Microphone

Step 23: Waterproof Test

Close the box, plug connectors and bring it in the shower. If no water comes through, we can mount all the electronic parts.

Step 24: Raspi and Raspiaudio

Screw the Pi Zero in and connect the soundcard. Mount the support for the circuit.

Step 25: Circuit

Mount the circuit and connect all the components. Plug a battery.

Step 26: Done!

The system is complete! The SD can easily be accessed through the whole at the bottom.

Step 27: Setup a Remote Supercollider Server

sudo apt-get install supercollider
scsynth -u 57110 -B 0.0.0.0 -z 4

Step 28: PCM Daemon

In this step we daemonize our Python Power Cycle Manager to have it always running in the background. The script will take care of shutting down the Pi when it's time. Download the attached Python file and save it in "/home/pi/src/python/main.py". Then, in a terminal:

cd /lib/systemd/system
sudo nano kn.service

Edit and save:

[Unit]
Description=Klangnetze PCM
After=multi-user.target

[Service]
Type=simple
User=pi
ExecStart=/usr/bin/python3 /home/pi/src/python/main.py
Restart=on-abort

[Install]
WantedBy=multi-user.target

Then:

sudo chmod 644 /lib/systemd/system/kn.service
chmod +x /home/pi/src/python/main.py
sudo systemctl enable kn.service
sudo systemctl start kn.service

Daemon should be running. To test:

sudo systemctl status kn.service

If you get:

● kn.service - Klangnetze PCM
     Loaded: loaded (/lib/systemd/system/kn.service; enabled; vendor preset: en>
     Active: active (running) since Wed 2023-01-25 19:10:38 CET; 18min ago
   Main PID: 505 (python3)
      Tasks: 1 (limit: 407)
        CPU: 917ms
     CGroup: /system.slice/kn.service
             └─505 /usr/bin/python3 /home/pi/src/python/main.py

It's working properly.

Daemonization adapted from this guide.

Attachments

Step 29: PCM in LXDE at Startup

cd /etc/xdg/lxsession/LXDE-pi
sudo nano autostart
@lxterminal --command="/home/pi/src/python/start.sh"