commit 822ce623ea3b23dd568f1c64e155b6ccd6767883 Author: my Date: Mon Jun 8 11:38:58 2026 +0200 intial diff --git a/3D model/Modified stamp 110prc.3mf b/3D model/Modified stamp 110prc.3mf new file mode 100644 index 0000000..f15d245 Binary files /dev/null and b/3D model/Modified stamp 110prc.3mf differ diff --git a/3D model/Modified stamp.blend b/3D model/Modified stamp.blend new file mode 100644 index 0000000..9ea3dcb Binary files /dev/null and b/3D model/Modified stamp.blend differ diff --git a/3D model/Modified stamp.stl b/3D model/Modified stamp.stl new file mode 100644 index 0000000..f803ee9 Binary files /dev/null and b/3D model/Modified stamp.stl differ diff --git a/Code/clay_mesh_workshop/clay_mesh_workshop.ino b/Code/clay_mesh_workshop/clay_mesh_workshop.ino new file mode 100644 index 0000000..4c040a8 --- /dev/null +++ b/Code/clay_mesh_workshop/clay_mesh_workshop.ino @@ -0,0 +1,166 @@ +/*=================================================== + * Clay PCB Workshop — Mesh Node + * + * Change NODE_ID before flashing each board. + * + * D11 — trigger input (button, sensor etc) + * A0–A5 — outputs 1–6 + * D13 — output 7 + * D2 — network bus (shared wire between all nodes) + * D5 - led pin for feedback + * + * When trigger fires -> sends NODE_ID to all nodes + * When message N arrives -> activates output[ N % 7 ] + * + * node 1 -> A5 | node 2 -> A4 | node 3 -> A3 + * node 4 -> A2 | node 5 -> A1 | node 6 -> A0 | node 7 -> D13 + * node 8 -> A5 (wraps around)... + * + * Bus wiring: one wire shared between all nodes on D9, + * one 4.7kΩ pullup to 5V anywhere on bus. + * one shared ground wire. + *===================================================*/ + +#define NODE_ID 2 // <- change this for each board, starts at a humanfriendly #1 + +/* +┌─────────────────────────────┐ +| EXAMPLE: | +│ YOU ARE NODE 1 │ +│ Your trigger: wire on D11 │ +│ │ +│ When YOU press → A5 on │ +│ every board reacts │ +│ │ +│ Your board reacts to: │ +│ A5 <- Node 1 (you) │ +│ A4 <- Node 2 │ +│ A3 <- Node 3 │ +│ A2 <- Node 4 │ +│ A1 <- Node 5 │ +│ A0 <- Node 6 │ +│ D13 <- Node 7 │ +└─────────────────────────────┘ +*/ + +#define BUS_PIN 2 +#define TRIGGER_PIN 11 + +const uint8_t OUTPUT_PINS[] = { A5, A4, A3, A2, A1, A6, 13 }; +#define NUM_OUTPUTS 7 +#define OUTPUT_MS 1000 // how long an output stays on (milliseconds) + +#define BIT_US 1600 // bit period — long enough for 8MHz + oscillator drift +#define START_US 3200 // start pulse length + +unsigned long outputOffAt[NUM_OUTPUTS]; + +#define LED_PIN 5 // slow blink pin to test if the sketch is running (its not broken out, but close to ground so you can hold a led to it) +static unsigned long ledChangeAt = 0; // timing for the led blink +static bool ledOn = false; + +void setup() { + Serial.begin(9600); + Serial.print("Node "); + Serial.println(NODE_ID); + + pinMode(TRIGGER_PIN, INPUT_PULLUP); + pinMode(BUS_PIN, INPUT_PULLUP); + pinMode(LED_PIN, OUTPUT); + + for (int i = 0; i < NUM_OUTPUTS; i++) { + pinMode(OUTPUT_PINS[i], OUTPUT); + digitalWrite(OUTPUT_PINS[i], LOW); + outputOffAt[i] = 0; + } + + // Blink own output pin and LED_PIN times on startup to confirm ID + int myOutput = OUTPUT_PINS[NODE_ID % NUM_OUTPUTS]; + for (int i = 0; i < NODE_ID; i++) { + digitalWrite(myOutput, HIGH); + digitalWrite(LED_PIN, HIGH); + delay(100); + digitalWrite(myOutput, LOW); + digitalWrite(LED_PIN, LOW); + delay(400); + } + delay(1000); // wait a bit for clarity +} + + +void loop() { + // Turn off outputs whose timer has expired + unsigned long now = millis(); + for (int i = 0; i < NUM_OUTPUTS; i++) { + if (outputOffAt[i] > 0 && now >= outputOffAt[i]) { + digitalWrite(OUTPUT_PINS[i], LOW); + outputOffAt[i] = 0; + } + } + + // Send NODE_ID when trigger fires (INPUT_PULLUP -> active LOW) + if (digitalRead(TRIGGER_PIN) == LOW) { + sendByte(NODE_ID); + Serial.print("sent"); + delay(250); // debounce + } + + // Listen for incoming messages + int msg = readByte(); + if (msg > 0) { + int idx = (msg - 1) % NUM_OUTPUTS; + digitalWrite(OUTPUT_PINS[idx], HIGH); + outputOffAt[idx] = millis() + OUTPUT_MS; + Serial.print("received "); + Serial.println(msg); + } + + // slow blink a pin for testing + now = millis(); // even recycle variables ;) + if (now >= ledChangeAt) { + if (!ledOn) { + digitalWrite(LED_PIN, HIGH); + ledOn = true; + ledChangeAt = now + 20; // stay on 100 ms + } else { + digitalWrite(LED_PIN, LOW); + ledOn = false; + ledChangeAt = now + 5000; // stay off 1000 ms + } + } +} + +void sendByte(byte b) { + pinMode(BUS_PIN, OUTPUT); + + digitalWrite(BUS_PIN, LOW); // start pulse + delayMicroseconds(START_US); + + for (int i = 0; i < 8; i++) { // 8 data bits + digitalWrite(BUS_PIN, (b >> i) & 1); + delayMicroseconds(BIT_US); + } + + digitalWrite(BUS_PIN, HIGH); // stop + delayMicroseconds(BIT_US); + + pinMode(BUS_PIN, INPUT_PULLUP); +} + + +int readByte() { + pinMode(BUS_PIN, INPUT_PULLUP); + + if (digitalRead(BUS_PIN) == HIGH) return -1; // bus idle, nothing to read + + delayMicroseconds(START_US + BIT_US / 2); // skip start pulse, land mid bit-0? + + byte value = 0; + for (int i = 0; i < 8; i++) { + value |= (digitalRead(BUS_PIN) << i); + delayMicroseconds(BIT_US); + } + + if (value == 0) return -1; // discard empty reads + return value; +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..8f19963 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# Clay PCB mesh + +Code and other resources for the workshop Earthbound Hardware, as part of the Connecting Otherwise artistic research consortium. +Based on the original research and documentation of Patrícia J. Reis and Stefanie Wuschitz: +https://github.com/FeministHardware/Making-PCBs-from-natural-clay/tree/main + +## "Mesh network" +The goal is to create a symbolic 'mesh' network using the clay pcbs. +Pressing a button on one node sends a signal across a shared two-wire bus, all other nodes blink a pin in response corresponding to the senders ID. +We tried to keep the parts count minimal as possible (just a resistor and conductive material). + +RS232 did not fit because assumes a hierarchy, one device is always in charge, others respond. RS485 avoids that but needs an extra hardware, a transceiver chip on every node that were hard to source as used. +Instead we ended up on bitbanging, the nodes communicate by directly toggling a pin, a bit like morsecode. It keeps the circuit as bare as possible: two wires, a pull-up resistor, and whatever conductive material you find to connect the PCB's together. + +## Code + +Communication uses bitbanging over a half-duplex two-wire bus (signal pulled up with a 4.7kΩ resistor). +Each node: +- Has a unique NODE_ID (set in the sketch, values up to ~32) +- Sends its ID on the bus when the button is pressed +- Blinks its LED when it receives any message + +Because everything runs in the main loop with delayMicroseconds, avoid using delay() elsewhere as it will break communication. + +Before uploading, set a unique NODE_ID per node: +```cpp +#define NODE_ID 3 // change for each node +``` + +## Hardware modifications +The stamp used to press the PCB traces into clay has been modified: +- The trace between the motor driver circuit and pin 9 is removed. +- Two additional magnet/connection points have been added to allow nodes to connect to the shared bus. + +One of the needs needs to pull up the bus wire with a 4.7ohm resistor! +To do this add a resistor between one of the 5V connection points (the 5V input makes sense) and the bus pin (D2). \ No newline at end of file diff --git a/presentation.odp b/presentation.odp new file mode 100644 index 0000000..f1c55e3 Binary files /dev/null and b/presentation.odp differ