Talking Books
Vijf boeken fluisteren tot je er een oppakt, en laten dan op een e-ink scherm zien wat ze te vertellen hebben.
Op een leestafel staan vijf boeken, elk in een eigen houder. Je hoort ze fluisteren, en ze lokken je dichterbij. Op het schermpje in elke houder staat een citaat uit het boek met het paginanummer erbij, telkens een ander, als uitnodiging om het boek op te pakken en naar die bladzijde te bladeren. Til je het op, dan stopt het fluisteren en toont het scherm titel en auteur, zodat je weet waar het boek terug moet. Zet het terug en de stilte vult zich weer. De installatie onthoudt welk boek hoe lang is opgepakt.
Ik heb de fysieke uitwerking gedaan: de elektronica ontworpen, gesoldeerd en ingebouwd, en de firmware geschreven. In elke houder zit een Raspberry Pi Pico 2 W, een e-ink scherm van 128 bij 296 pixels, een infrarood-lichtsluis, een versterker en een luidspreker. De Pico leest de sensor tien keer per seconde uit, speelt geluid af over I2S en toont het beeld dat hij als ruwe pixels van de server ontvangt; de inhoud staat op een server en is makkelijk aan te passen zonder Pico’s opnieuw te flashen. Voor de verbinding schreef ik een websocket-client voor MicroPython en ExpOS-server. Elke Pico houdt contact met de ExpOS-server op een Raspberry Pi 5, pingt elke dertig seconden en verbindt zelf opnieuw als de wifi wegvalt. Een microcontroller start in een seconde en kan van de stroom af zonder afsluiten, wat in een museum elke avond gebeurt. De houders zijn 3D-geprint en onder de tafel doorgelust.
Colofon
- Getoond: vanaf augustus 2025, Vrouwen als technologie, Design Museum Den Bosch
- Studio: Scape Agency, op het ExpOS-platform
- Mijn aandeel: elektronica, firmware, websocket-client, inbouw
Code
Hoe een afbeelding op de server de ruwe pixels wordt die de Pico op het e-ink scherm zet, ingekort. Eén bit per pixel, acht pixels per byte, in het MONO_HLSB-formaat dat MicroPython zelf ook gebruikt; een scherm van 128 bij 296 pixels is zo 4.736 bytes.
def create_framebuffer_mono_hlsb(image_bytes, width=128, height=296, threshold=127):
"""Grayscale bytes in, MONO_HLSB framebuffer out."""
framebuffer = bytearray()
for y in range(height):
for x in range(0, width, 8):
byte_val = 0
for bit in range(8):
if x + bit < width:
pixel_idx = y * width + x + bit
if pixel_idx < len(image_bytes):
# boven de drempel is wit (1), anders zwart (0)
pixel_val = 1 if image_bytes[pixel_idx] > threshold else 0
byte_val |= pixel_val << (7 - bit) # meest significante bit eerst
framebuffer.append(byte_val)
return bytes(framebuffer)
# Daarna base64 in een websocket-bericht naar de Pico
framebuffer_b64 = base64.b64encode(framebuffer_bytes).decode("ascii")