Plushie . OSC Controller Via WiFi . Soft and Squishy Memories Container.

by fantasiasperifericas in Circuits > Gadgets

44 Views, 1 Favorites, 0 Comments

Plushie . OSC Controller Via WiFi . Soft and Squishy Memories Container.

pelushe.png
foto_detalle05.png
foto_detalle01.png
foto_detalle03.png

This project proposes the creation of an open-source interactive plush toy designed to activate encounter, listening, rest, and collective reflection.

A soft and gentle plush that sends OSC over WiFi through interaction with its piezoelectric sensors.

When any of its contact microphones are pressed, it sends OSC signals that can be received by any software compatible with the protocol. In this case, we use the free software audistellar.xyz to activate and deactivate different sound constellations.

Its LED lights each correspond to a different constellation, turning on or off to indicate whether a sequence is active or muted.

These constellations bring together the voices of queer and migrant people. They were created from fragments of interviews extracted from Chapter 3: Exile of the podcast from the Archivo de la Memoria Trans Argentina. The AMT was one of our main inspirations in the development of this device.


A soft plush cushion-like object.

I would like it to be much more organic.

Like hugging a cat.

Enjoying softness.

Resting in tenderness.

Something to travel through and gather.

To recover, to archive.

A portable place of care and perspective.

That plush toy you carry everywhere, helping you remember other moments, other spaces.

A portable shelter of our collective memories.

Filled with queer and migrant voices that speak to us slowly, making us think and activating deep reflections about who we are, how we are, and how we might become—collectively.


Supplies

Electronics

  1. 1 Arduino Uno R4 WiFi
  2. Rechargeable battery with USB-C cable
  3. 1 PCB board
  4. Pin header strip for Arduino
  5. 6 piezoelectric sensors
  6. 6 LED diodes
  7. 6 resistors (220Ω–330Ω)
  8. Soldering iron
  9. Solder wire
  10. Heat-shrink tubing
  11. 12 m of 0.5 mm cable in one color for GND identification
  12. 6 m of 0.5 mm cable in another color for piezos
  13. 6 m of 0.5 mm cable in another color for LEDs


Plush Body

  1. Pillow or plush base
  2. Fabrics
  3. Needles
  4. Pins
  5. Scissors
  6. Thread


Natural Fabric Dye (Optional)

  1. Beetroot (for organic dye)
  2. Blender or food processor
  3. Fine fabric mesh or cheesecloth
  4. Basin or container for dye bath
  5. Rope and clothespins for drying the dyed fabric

PCB Assembly

diagramas_espejopelushe_Pelushe.jpg

Assemble a PCB that integrates the Arduino R4 WiFi, the piezoelectric sensors, and the LEDs with their respective resistors.

This board helps organize the circuit and distribute all connections inside the plush body in a more stable, clean, and modular way.

The PCB makes it easier to:

  1. Reduce cable clutter inside the plush
  2. Improve structural stability of the electronics
  3. Simplify maintenance, repair, and future modifications

An electronic schematic is included as a reference to support the reconstruction and/or adaptation of the project.


Upload the Code

This code receives the electrical impulses generated by contact with the piezoelectric sensors and converts them into OSC signals, which are then sent to the AudioStellar software port. These signals mute or unmute different sound sequences, while the corresponding LEDs turn on or off to indicate whether each sequence is active or not.


In the first section, RED/OSC, you will need to enter the WiFi network you are using, its password, and your IP address so that the system works in your location.


Upload the code to the Arduino R4 WiFi.



#include <WiFiS3.h>
#include <ArduinoOSCWiFi.h>

// ================== RED / OSC ==================
const char* RED_WIFI = "network";
const char* CLAVE_WIFI = "pass";
const char* IP_OSC_AS = "ip dir";
const int PUERTO_OSC_AS = 8000;


// ============= PIEZOS EN PINES ANALÓGICOS A0-A5 =============
const int N_PIEZOS = 6;
const int PINES_PIEZOS[N_PIEZOS] = {A0, A1, A2, A3, A4, A5};
const char* NOMBRES_PIEZOS[N_PIEZOS] = {"A0","A1","A2","A3","A4","A5"};

const int CONSTELACION[N_PIEZOS] = {0, 1, 2, 3, 4, 5}; // Mapeo a CONSTELACION (AudioStellar)

// ============= LEDS =============
const int PINES_LEDS[N_PIEZOS] = {11, 7, 12, 8, 10, 9};


// ======== SUAVIZADO MUESTREO =========
const uint8_t MUESTRAS_PROMEDIO_ADC = 1; // Número de lecturas para promediar la señal analógica
const int RETARDO_US_ADC = 0; // Retardo entre lecturas analógicas en microsegundos
float alphaLineaBase = 0.0020f; // Factor de suavizado para la línea base
float alphaDiferencia = 0.70f; // Factor de suavizado para la diferencia de señal
int muestreoInicialLineaBase = 600; // Número de muestras para calcular la línea base inicial

// ================== SENSIBILIDAD ==================
int umbralPin[N_PIEZOS] = {80, 80, 80, 120, 80, 80}; // Si la señal del piezo supera este valor, se considera una activación
int pendienteMinPin[N_PIEZOS] = {20, 20, 20, 30, 20, 20}; // Pendiente mínima entre lecturas consecutivas para que se considere una activación
int golpesConsecutivosNecesarios[N_PIEZOS] = {1, 1, 1, 1, 1, 1};
int umbralSilencioPin[N_PIEZOS] = {28, 28, 28, 28, 28, 28}; // Si la señal baja de este valor, se considera que el piezo está en reposo
unsigned long tiempoRearmarSilencioMs[N_PIEZOS] = {80, 80, 80, 80, 80, 80}; // Tiempo en milisegundos que debe pasar en silencio antes de rearmar el piezo previniendo falsas activaciones
unsigned long tiempoRefraccionMs[N_PIEZOS]= {130,130,130,130,130,130}; // Impide que un mismo golpe se cuente varias veces consecutivas

// ================== ESTADOS ==================
int lineaBase[N_PIEZOS];
float diferenciaSuavizada[N_PIEZOS];
int ultimaDiferencia[N_PIEZOS];
bool piezoArmado[N_PIEZOS];
unsigned long silencioMs[N_PIEZOS];
int contadorExceso[N_PIEZOS];
unsigned long ultimoActivePiezoMs[N_PIEZOS];
bool estadoSecuencia[N_PIEZOS] = {false,false,false,false,false,false}; // Estado ON/OFF

// ================== UTIL ==================
int leerPromedioAnalogico(uint8_t pin, uint8_t n = MUESTRAS_PROMEDIO_ADC) {
long acc = 0;
for (uint8_t i = 0; i < n; i++) {
acc += analogRead(pin);
if (RETARDO_US_ADC > 0) delayMicroseconds(RETARDO_US_ADC);
}
return (int)(acc / (n ? n : 1));
}

// ================== WIFI ==================
void asegurarWifi() {
static unsigned long ultimaRevision = 0;
unsigned long ahora = millis();
if (ahora - ultimaRevision < 250) return;
ultimaRevision = ahora;

if (WiFi.status() == WL_CONNECTED) return;
Serial.println("[WiFi] Intentando conectar");
WiFi.disconnect();
delay(100);
while (WiFi.begin(RED_WIFI, CLAVE_WIFI) != WL_CONNECTED) delay(200);
Serial.println("[WiFi] CONECTADO :)");
}

// ================== SETUP ==================
void setup() {
Serial.begin(115200);
while (!Serial) {}

WiFi.begin(RED_WIFI, CLAVE_WIFI);
Serial.print("[WiFi] IP Arduino: ");
Serial.println(WiFi.localIP());

Serial.print("[OSC] Destino: ");
Serial.print(IP_OSC_AS);
Serial.print(":");
Serial.println(PUERTO_OSC_AS);

// ---- LEDs ----
for (int i=0; i<N_PIEZOS; i++) {
pinMode(PINES_LEDS[i], OUTPUT);
digitalWrite(PINES_LEDS[i], LOW);
}

// ---- lineaBase inicial ----
for (int i = 0; i < N_PIEZOS; i++) {
long acc = 0;
for (int j = 0; j < muestreoInicialLineaBase; j++) {
acc += leerPromedioAnalogico(PINES_PIEZOS[i]);
delay(3);
}
lineaBase[i] = acc / muestreoInicialLineaBase;

diferenciaSuavizada[i] = 0;
ultimaDiferencia[i] = 0;
piezoArmado[i] = true;
silencioMs[i] = millis();
contadorExceso[i] = 0;
ultimoActivePiezoMs[i] = 0;

Serial.print("[Piezo "); Serial.print(NOMBRES_PIEZOS[i]);
Serial.print("] lineaBase = "); Serial.println(lineaBase[i]);
}
}

// ================== LOOP ==================
void loop() {
asegurarWifi();
unsigned long ahora = millis();

for (int i = 0; i < N_PIEZOS; i++) {

// -------------------- Lectura --------------------
int raw = leerPromedioAnalogico(PINES_PIEZOS[i]);
lineaBase[i] = (1.0f - alphaLineaBase) * lineaBase[i] + alphaLineaBase * raw;
int diff = abs(raw - lineaBase[i]);

diferenciaSuavizada[i] = (1.0f - alphaDiferencia) * diferenciaSuavizada[i] + alphaDiferencia * diff;
int diffF = (int)diferenciaSuavizada[i];
int slope = diffF - ultimaDiferencia[i];

// -------------------- Arming --------------------
if (diffF < umbralSilencioPin[i]) {
if (!piezoArmado[i]) {
if (ahora - silencioMs[i] >= tiempoRearmarSilencioMs[i]) {
piezoArmado[i] = true;
contadorExceso[i] = 0;
}
} else {
silencioMs[i] = ahora;
}
} else if (piezoArmado[i]) {
silencioMs[i] = ahora;
}

// -------------------- Conteo --------------------
bool over = (diffF > umbralPin[i]);
if (over) contadorExceso[i]++; else contadorExceso[i] = 0;

// -------------------- HIT DETECTADO --------------------
if (piezoArmado[i] &&
contadorExceso[i] >= golpesConsecutivosNecesarios[i] &&
slope >= pendienteMinPin[i] &&
(ahora - ultimoActivePiezoMs[i] >= tiempoRefraccionMs[i])) {

ultimoActivePiezoMs[i] = ahora;
piezoArmado[i] = false;
silencioMs[i] = ahora;
contadorExceso[i] = 0;

// Toggle de estado de la secuencia
estadoSecuencia[i] = !estadoSecuencia[i];

// LED refleja estado de la secuencia
digitalWrite(PINES_LEDS[i], estadoSecuencia[i] ? HIGH : LOW);

// OSC INVERTIDO para que coincida con el LED
char addr[32];
snprintf(addr, sizeof(addr), "/trigger/%d", CONSTELACION[i]);
OscWiFi.send(IP_OSC_AS, PUERTO_OSC_AS, addr, estadoSecuencia[i] ? 0 : 1);

Serial.print("Piezo ");
Serial.print(NOMBRES_PIEZOS[i]);
Serial.print(estadoSecuencia[i] ? " -> SECUENCIA ON" : " -> SECUENCIA OFF");
Serial.print(" -> OSC ");
Serial.println(addr);
}

ultimaDiferencia[i] = diffF;
}
}

Choosing the Materials for the Plushie

Find a cushion or plushie that makes you want to cuddle and hold it for a long time.

For this project, we chose a cylindrical cushion because it allowed us to imagine different ways of interacting with it and positioning the sensors. We then covered it in soft, fluffy fabric dyed with beetroot dye. Alternatively, you could use any existing cushion or soft toy and adapt it to your liking.

The idea is to start with a comfortable, soft and friendly object.

If necessary, explore different fabrics and soft materials, observing their colours, textures and even their smells (you could even apply essential oils or other scents).

Look for materials that you feel comfortable spending a long time with.

It is essential that the object is pleasing to the senses.

Stuff the Plushie With Its Electronic Components

IMG_8241.png

Fit all the electronics inside the soft toy.

Use an external battery to power the system and make an opening in the body of the soft toy to insert:

The PCB board

The Arduino

The wiring

The battery

Leave space for the cables to exit.

Ensure that all components are protected, accessible and convenient for everyday use.

Making Their Clothes

IMG_8236.png
peluche04.jpg

Cut the fabric to the dimensions of the chosen cushion.

In our case, as it is a cylinder, we made two circles for the sides and a rectangle to wrap around it horizontally.

Use pins to mark the sides that will later be sewn together. This helps you to visualise the final shape of the soft toy more clearly and allows you to keep adjusting until you achieve the desired shape when working without a pattern.

Cut small openings in the fabric for each piezo. Think of each sensor as a distinct extension of the soft toy’s body:

Some piezos can be attached directly to the main body.

Others can be connected via long wires, functioning as small limbs, tails or sensitive appendages.

Explore different ways of physical interaction between the fabric body and the sensors.

Make small pockets of different textures to cover the piezoelectric elements. They can be more or less exposed as desired.

The pockets can be sewn over the holes to keep them in place and ensure all the wires are inside. In our case, we liked the idea of showing its innards, so we left them sticking out.

Once you’ve tested it and are happy with it, sew everything together.

If you’re not great at sewing, don’t worry – choose a plush fabric with long pile and that will hide everything ;)

Dyeing Fabric With Beetroot

remolatxa.jpg

*We wanted to dye the fabric we chose using something more organic that has a sweet smell. This is entirely optional. However, we encourage you to indulge in any similar whims that come your way during the process, and we’ve included the instructions anyway:

Once you’ve chosen your pieces of fabric, begin the organic dyeing process using beetroot.

To make the dye:

Get some beetroots. If they have leaves, trim them off and save them (in the fridge, wrapped in paper and a plastic bag for better preservation). You can use them later to make salad or puddings.

Wash them and cut off all the ends and any remaining stalks. Set aside the central parts.

Place the scraps in a food processor and blend them as much as possible, stirring occasionally.

Strain this processed juice through a piece of muslin or a fine-mesh cloth to separate the liquid from the fibre.

This liquid will be our dye, and it is important that it contains no solid residue. Strain as many times as necessary.

The beetroot centres that we set aside can be cooked and eaten. As well as dyeing fabric, the dye can be used for painting, writing or making antotypes (photographic prints using organic pigments).

Dip the fabric into the dye or apply it with a spray bottle or brush, depending on the desired effect.

Leave to dry.

Prepare the Audiostellar Project With the Sound Archive

peluche-1024x323.png

Select and edit audio clips from the Archivo de la Memoria Trans Argentina — a community-led archive preserving recordings, testimonies, and personal memories of the Argentine trans community from the 1970s to the 1990s.

The archive can also be expanded with personal memories, intimate sound recordings, or audio fragments collected from the participant’s.

Subsequently integrate these audio clips into AudioStellar using different units to define specific sound variations and behaviours for each piezoelectric element.

Associate each sensor with a different sound response to create a responsive and dynamic experience.


Attach:

Screenshots of the audio folders used

The final selection of audio clips

Project settings in AudioStellar

to facilitate the exploration and reuse of the material.

Creating a Meeting Place

pelushe
04.jpg
05.jpg
01.JPG
08.JPG
09.JPG
10.JPG
11.JPG

Create a space for relaxation and listening where the soft toy can be used.

Include:

Blankets

Soft lighting

Comfortable surfaces

The AudioStellar interface displayed on screen

The aim is to complement the tactile and auditory experience with a warm and peaceful atmosphere.