Skip to content

11. Open Source Hardware - From Fibers to Fabric

weekly assignment

Learning outcomes

  • Research skills: the participant has acquired knowledge through references and Concept development
  • Design skills: the participant has learnt through sketches, 3D modeling, use of electronics, etc
  • Fabrication skills: the participant is capable of executing from file to production workflow, from 3D modelling to digital fabrication, electronics, materials
  • Process skills: Anyone can go through the process, understand it and reproduce it
  • Final outcome: The assignment is assembled and either complete or tested = Originality: Has the design been thought through and elaborated?

Student checklist

  • Research and document existing fabrication methods, machines and industries, add references, tutorials and sketches of the hardware you will make
  • Document the process of designing the files for your machine/machine-hack/tool and its fabrication including the assembly process
  • Document the schematic and the software source code (if any)
  • Document the parts and how to make your tool or machine
  • Document your BOM (Bill of materials): electronics, materials, their amount, etcetera (with references of the components)
  • Upload your 3D model and CAM files (if any)
  • Design, create and document a final outcome, a sample project of your process
  • Make a small video of the machine
  • Create an interface for controling your machine (extra credit)

Check out the weekly assignment here

Research & Ideation

get inspired!

Check out and research alumni pages to betetr understand how to document and get inspired

References & Inspiration

text I have long been fascinated by weaving and looms. So the portable loom projects from the Fab and Fabri communities have always been a favourite.

I met Walter in Bhutan at Fab23 and discovered a version of the FabLoom / SheMakes loom in a workshop he was taking, and eventually made one for myself.


Find the longer version of that story on my Cabinet of Curiosities website.

From my visits with the weavers of Kutch as well, I am always enthralled by their work. text

Another fantastic open source project I have long been a fan of is the Open Press Project.

Among other things, they have the files, documentation and instructions for open source, 3D printable mini presses.

Beyond these, I found other weaving and braiding machines interesting. Especially interesting in both the main session as well as the tutorial were the software/interface/fileType aspect, because I find too few people address/are inteested in that.
text text

The ability to encode data in knits and weaves is astonishing, and it has been in use for ages. The one that sticks in my mind is that during the French revolution, the common people would record names of the guillotined and the not-yet within their knitting.

The circular knitting machine is also very interesting, and I've imagined adding a motor to the toy version to run it faster. The Tufting gun is also a popular activity that I'd like to try out.

text text

Using a plotter to plot wax lines and do batik is simply brilliant. text

I had some ideas along similar lines during Textile Scaffolding as well. The Fibre Gun looks very interesting to use. The Alginate rollers are a very simple but elegant way to coat and create bio-composites.

text text

Ideation

I had a number of ideas, listed below

  • Thread-winder 3D printing - A winding-drum spool that gets contours built on it by depositing thread
  • Arduino mini-loom - a programmable pattern loom
  • Braiding machines

Something like the Braiding machine would also be very interesting. text text

3D Printed Braiding Machine

I attempted the first, failed, and attempted the second.

Thread Winder - String 3D Printing

Concept

I saw this thread spooling device during our visits to Kutch.

text text

text

A machine that winds thread on a spindle core; the thread is moistened with glue by passing through a hopper/glue chamber; the thread source moves along one axis to control location of deposition on cylinder; the thread builds up on the core to create a 3d volumetric form, of cylindrical symmetry; ergo, thread 3D printing.

Initial - using basic tools and an electric screwdriver or powerdrill to spin the spindle and manually control the linear direction Final - cylindrical speed control + linear axis control + software to work out thread layers and move linear axis accordingly to deposot more or less thread in a region

Core can be slender - a pencil or bolt - to create forms; Core can be a larger cylinder that cna later be released - to create hollow boxes/containers with decorative outer shells

Use p5.js or other code to create a "spool path" from the input profile that controls the linear location of the source spool.

Trial

text text text

When I tried the manual version, I hit a snag. The contour could not be built, try as I might. I kept the sting source far away, and I brought it up close, but the string landing poing kept wobbling over the surface.

My guess is that there is some kind of "angle of repose" or "heaping angle" effect at play here, that things will roll off beyond a certain angle of steepness. This will effectively prevent it from building any contours.

Reference : Angle of Repose, Wikipedia

Arduino Loom

Overall Concept

text

I wanted to begin with a small programmable loom that could be expanded later, rather than trying to build the entire system at once.

The project was divided into two phases:

  • Phase 1 focuses on controlling the warp threads electronically using a binary pattern stored in the Arduino code.
  • Phase 2 proposes moving the pattern out of the code and encoding it physically using a punch-card strip.

Phase 1 allows me to test:

  • Whether individual warp threads could be controlled using small servo motors
  • Whether eight servos could be operated from one Arduino Uno
  • Whether a binary image could be converted into a usable weaving sequence
  • Whether the loom could move through the sequence one row at a time

Phase 2 would build on this by adding:

  • A punch-card reader
  • LDR sensors
  • A light source
  • A stepper-driven card-feed mechanism
  • A way to change the weaving pattern without editing and uploading the Arduino code each time

Phase 1 — Programmable Mini-Loom

Concept

The first phase focuses on controlling the warp threads electronically:

  • The prototype has eight independently controlled warp threads.
  • Each warp thread is controlled by one SG90 servo motor.
  • The servos move the heddles up or down to create the required shed.
  • An Arduino Uno controls the eight servos.
  • The weaving pattern is stored as a binary grid:
  • 1 moves a servo to the raised position.
  • 0 moves a servo to the lowered position.
  • A pushbutton advances the loom to the next row of the pattern.
  • The shuttle is passed manually.
  • Once the final pattern row is reached, the program loops back to the first row.

Tools

Mechanical Design

The Phase 1 prototype is based on a small, expandable loom with eight warp channels.

The main mechanical elements are:

  • A frame that holds the warp threads in position
  • Eight servo motors arranged along the loom
  • One servo-controlled heddle connection for each warp thread
  • Supports that keep the servos and warp-control mechanism aligned
  • A manually operated shuttle for passing the weft

Each servo controls one warp channel:

  • One servo position raises the associated heddle or warp thread.
  • The opposite servo position lowers it.
  • The combination of raised and lowered threads creates the shed for each row.
  • The shuttle is then passed manually through the shed.

The loom was kept small so that I could first test the heddle-control mechanism.

The number of warp threads can later be increased by:

  • Adding more servo positions
  • Widening the frame
  • Adding additional controller boards
  • Dividing the loom into repeated eight-channel modules

Electronics

The Phase 1 electronics consist of:

  • 1 Arduino Uno
  • 8 SG90 servo motors
  • 1 momentary pushbutton
  • Wiring between the Arduino, servos and button
  • A power source for the Arduino and servo motors

The eight servo signal pins used in the current code are:

  • Servo 1 — Pin 3
  • Servo 2 — Pin 5
  • Servo 3 — Pin 6
  • Servo 4 — Pin 9
  • Servo 5 — Pin 10
  • Servo 6 — Pin 11
  • Servo 7 — Pin 12
  • Servo 8 — Pin 13

The pushbutton is connected to:

  • Pin 2
  • Ground when pressed
  • The Arduino's internal pull-up resistor using INPUT_PULLUP

The servo positions are currently defined as:

  • 90° — neutral position
  • 180° — raised position
  • — lowered position

Coding

Pattern Generator

I used p5.js to convert an image into a binary weaving pattern.

The pattern generator:

  • Loads an image
  • Resizes it to a smaller grid
  • Reads the RGB value of every grid cell
  • Calculates its average brightness
  • Compares the brightness against a threshold value
  • Converts the cell into either 1 or 0
  • Stores the values as a two-dimensional array
  • Displays a pixelated preview of the result
  • Prints the binary array to the browser console

The threshold controls which pixels become raised or lowered warp threads:

  • Pixels darker than the threshold become 1.
  • Pixels lighter than the threshold become 0.

The resulting array can then be copied into the Arduino sketch as the loom pattern.

For the current eight-thread prototype:

  • The number of columns should be set to 8.
  • Each column corresponds to one servo and one warp thread.
  • The number of rows can vary depending on the length of the pattern.
Pattern Generator Code

Pattern Generator in p5.js

let weaveImage = "myImage.jpg"; 
let cols = 8;
let rows = 8;
let threshold = 128;

let img;
let weavePattern;

function preload() {
  img = loadImage(weaveImage);
}

function setup() {
  createCanvas(img.width, img.height);
  noLoop();

  // Make a copy and shrink it to grid size
  let small = img.get();   // copy to preserve original
  small.resize(cols, rows);  // resize image to grid

  // Generate 1/0 pattern
  small.loadPixels();
  weavePattern = [];

  for (let y = 0; y < rows; y++) {
    let row = [];
    for (let x = 0; x < cols; x++) {
      let idx = 4 * (y * small.width + x);
      let r = small.pixels[idx + 0];
      let g = small.pixels[idx + 1];
      let b = small.pixels[idx + 2];
      let bright = (r + g + b) / 3;
      row.push(bright < threshold ? 1 : 0);
    }
    weavePattern.push(row);
  }

  console.log("Weave pattern:", weavePattern);
  drawPixelated(weavePattern);
}

// Preview — unchanged
function drawPixelated(grid) {
  background(255);
  let cellW = width / cols;
  let cellH = height / rows;
  noStroke();
  for (let y = 0; y < rows; y++) {
    for (let x = 0; x < cols; x++) {
      fill(grid[y][x] === 1 ? 0 : 255);
      rect(x * cellW, y * cellH, cellW, cellH);
    }
  }
}
Arduino Servo Control

The Arduino program controls the eight servos and moves through the weaving pattern one row at a time.

The program:

  • Includes the Arduino Servo library
  • Creates an array of eight servo objects
  • Defines the pin used by each servo
  • Stores the weaving pattern as a two-dimensional binary array
  • Moves all servos to their neutral positions during setup
  • Uses a pushbutton to advance the pattern
  • Debounces the pushbutton to avoid multiple accidental triggers
  • Reads the next row of the pattern
  • Moves each servo to either the up or down angle
  • Loops back to the first row after the final row

The basic sequence is:

  1. Press the button.
  2. Advance to the next row.
  3. Read the eight binary values in that row.
  4. Move the corresponding servos.
  5. Pass the shuttle manually.
  6. Press the button again for the next row.
Arduino Code

Arduino Code for loom

#include <Servo.h>

//  CONFIGURATION 
const byte NUM_SERVOS = 8;
const byte NUM_ROWS   = 8;  // number of rows in the pattern

// Pins for the 8 servos
const byte servoPins[NUM_SERVOS] = {3, 5, 6, 9, 10, 11, 12, 13};

// Button pin
const byte buttonPin = 2;  // wired to GND when pressed, with INPUT_PULLUP

// Servo angles
const int NEUTRAL_ANGLE = 90;
const int UP_ANGLE      = 180;  // 90° forward from neutral
const int DOWN_ANGLE    = 0;    // 90° backward from neutral

// Debounce
const unsigned long DEBOUNCE_MS = 50;

//  PATTERN (BINARY GRID) 
// 1 = move servo to UP_ANGLE
// 0 = move servo to DOWN_ANGLE
const byte weavePattern[NUM_ROWS][NUM_SERVOS] = {
  {0, 0, 0, 1, 1, 0, 0, 0},
  {0, 0, 1, 1, 1, 1, 0, 0},
  {0, 1, 1, 0, 0, 1, 1, 0},
  {1, 1, 0, 0, 0, 0, 1, 1},
  {1, 1, 0, 0, 0, 0, 1, 1},
  {0, 1, 1, 0, 0, 1, 1, 0},
  {0, 0, 1, 1, 1, 1, 0, 0},
  {0, 0, 0, 1, 1, 0, 0, 0}
};

//  GLOBALS 
Servo servos[NUM_SERVOS];

int currentRow = -1;            // starts at -1 so first tap moves to row 0
bool lastButtonState = HIGH;    // because of INPUT_PULLUP
unsigned long lastDebounceTime = 0;

//  SETUP 
void setup() {
  // Attach servos and move them to neutral
  for (byte i = 0; i < NUM_SERVOS; i++) {
    servos[i].attach(servoPins[i]);
    servos[i].write(NEUTRAL_ANGLE);
  }

  // Button with internal pullup
  pinMode(buttonPin, INPUT_PULLUP);

  // Optional: for debugging over serial
  Serial.begin(9600);
  Serial.println("Servo weave pattern ready. Tap switch to step rows.");
}

//  LOOP 
void loop() {
  // Read the button
  bool reading = digitalRead(buttonPin);

  // Debounce logic
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > DEBOUNCE_MS) {
    static bool lastStableState = HIGH;
    if (reading != lastStableState) {
      lastStableState = reading;

      if (reading == LOW) {
        advanceRowAndMoveServos();
      }
    }
  }

  lastButtonState = reading;
}

//  FUNCTIONS 

// Advance to the next row of the binary grid and move all 8 servos
void advanceRowAndMoveServos() {
  // Move to next row (wrap around)
  currentRow = (currentRow + 1) % NUM_ROWS;

  Serial.print("Moving to row ");
  Serial.println(currentRow);

  // For each servo/column in this row:
  for (byte col = 0; col < NUM_SERVOS; col++) {
    byte bit = weavePattern[currentRow][col];

    int targetAngle;
    if (bit == 1) {
      targetAngle = UP_ANGLE;
    } else {
      targetAngle = DOWN_ANGLE;
    }

    servos[col].write(targetAngle);
  }

  delay(20);
}

Fabrication and Assembly

alt text

Calibration and Operation

Testing and Iterations

Final Outcome

Phase 2 — Punch-Card-Controlled Loom

Proposed Concept

The eventual aim is to move the pattern out of the Arduino code and encode it physically using a punch-card strip.

The proposed system would work as follows:

  • A row of holes in the punch card represents one row of the weaving pattern.
  • Each warp thread has a corresponding LDR sensor.
  • A light source is placed above the punch card.
  • Light passes through the punched holes and reaches the LDRs below.
  • The Arduino reads the LDR values and converts the physical row into a binary pattern.
  • The Arduino then moves each servo either up or down.
  • After the shuttle has been passed, the card advances to the next row.
  • A stepper motor would move the punch card forward by one step.

The punch-card strip could be:

  • Punched manually
  • Laser cut
  • Used as a linear strip
  • Joined into a loop for repeating patterns

This phase would make the loom programmable without needing to edit and upload the Arduino code each time.

Proposed Mechanical Design

Phase 2 adds a physical punch-card reader to the existing loom.

The proposed mechanical additions are:

  • A punch-card strip positioned between the light source and the LDR sensors
  • A row of eight sensing positions aligned with the eight warp channels
  • Feed wheels or sprockets that engage with the edges of the punch-card strip
  • A stepper motor that advances the strip one row at a time
  • Guides that keep the punch card aligned with the sensors
  • A removable or hinged section that allows the pattern strip to be loaded

The punch-card feed must:

  • Move by exactly one pattern row after each weaving cycle
  • Hold the card flat while it is being read
  • Prevent light from leaking between adjacent sensing positions
  • Work with either a linear strip or a repeating loop

Proposed Electronics

For each warp channel, Phase 2 requires:

  • 1 servo motor already present from Phase 1
  • 1 LDR sensor
  • 1 fixed resistor for the LDR voltage divider
  • 1 corresponding position on the punch card

For eight warp threads, this gives:

  • 8 servo control signals
  • 8 LDR readings
  • Stepper-motor control signals
  • An input to confirm that the shuttle has been passed and the system can advance

This makes the available pins on an Arduino Uno quite limited.

Possible ways to expand the system include:

  • Using an Arduino Mega
  • Using an I²C servo-driver module such as a PCA9685
  • Using additional microcontrollers as repeated eight-channel modules
  • Connecting the secondary controllers to a main controller through I²C
  • Using an analogue multiplexer if more sensor inputs are required

The Phase 2 electronics would also require:

  • A stepper motor
  • A compatible stepper-motor driver
  • A light source above the punch card
  • Eight LDR voltage-divider circuits
  • A method of shielding each LDR from neighbouring light
  • A suitable power supply for the servos, lights and stepper motor

Proposed Coding and Control Sequence

The Phase 2 code has not yet been developed.

The proposed program would:

  • Read the eight LDR sensor values.
  • Compare each value against a calibrated light threshold.
  • Convert the sensor readings into eight binary values.
  • Move the corresponding eight servos.
  • Wait for confirmation that the shuttle has been passed.
  • Move the punch card forward by one row.
  • Wait for the card and sensors to settle.
  • Read the next pattern row.
  • Repeat the process.

Additional code would be needed for:

  • Calibrating the LDR values
  • Compensating for differences between individual sensors
  • Controlling the stepper motor
  • Preventing the card from advancing more than one row
  • Detecting the beginning and end of a linear card
  • Repeating a pattern when a looped card is used
  • Communicating between multiple Arduino boards
  • Controlling the servos through an I²C servo-driver module
  • Reporting the current row and sensor readings through the Serial Monitor

Expansion and Scalability

The Phase 2 system could later be expanded by:

  • Increasing the number of warp channels
  • Using repeated eight-channel servo and sensor modules
  • Using a larger controller
  • Separating servo control and sensor reading across multiple boards
  • Connecting secondary controllers through I²C
  • Using looped cards for repeating patterns
  • Using longer linear cards for non-repeating patterns

Next Steps

The next steps for Phase 2 would be:

  • Test one LDR with a punched card
  • Test light shielding between adjacent sensing positions
  • Decide the punch-card row and column spacing
  • Design the card guides and feed wheels
  • Select a stepper motor and driver
  • Test one-row card advancement
  • Finalise the controller and pin arrangement
  • Develop the sensor-calibration code
  • Integrate the card reader with the existing servo loom
  • Test a complete repeating pattern

Bill of Materials

Phase 1 — Components Used

Bill of Materials

Arduino Loom — Current Prototype

Category Component / Material Specification Quantity Purpose / Notes
Electronics Arduino Uno ATmega328P development board 1 Controls the eight servo motors and reads the pushbutton input
Electronics Micro servo motors SG90, 9 g, 180° 8 One servo independently raises or lowers each warp thread
Electronics Momentary pushbutton Normally open tactile or panel-mount switch 1 Advances the loom to the next row of the programmed pattern
Electronics Jumper wires Male–male and/or male–female 1 set Connections between the Arduino, servos and pushbutton
Electronics Servo extension wires Three-core servo extensions, if required 8 Allows the servos to reach the controller without straining their leads
Electronics 5 V power supply Regulated supply, approximately 3 A 1 External power for the eight servos; the servo supply and Arduino must share a common ground
Electronics USB cable USB-A to USB-B 1 Programming and serial communication with the Arduino
Mechanical Servo horns Supplied with SG90 servos 8 Connect the servo shafts to the heddle or warp-control strings
Mechanical Servo mounting screws Supplied with the servos or equivalent 16 Two screws per servo for fixing the servos to the frame
Mechanical Laser-cut base and frame pieces Sheet material; type and thickness to be confirmed 1 set Holds and aligns the servos and loom mechanism
Mechanical 3D-printed mounting components PLA or equivalent filament 1 set Servo supports, rod holders, end brackets and connecting components
Mechanical Parallel rods / dowels Diameter and length to be measured from the prototype 2 Form the principal longitudinal structure of the loom
Mechanical General fasteners Nuts, bolts, washers and/or self-tapping screws 1 set Assembly of the frame and printed components; sizes to be confirmed
Loom components Warp-control cords Strong thread or fine cord 8 lengths Connect each servo horn to its corresponding warp thread or heddle
Loom components Warp yarn Suitable weaving yarn 8 ends minimum Eight independently controlled warp threads in the current prototype
Loom components Weft yarn Suitable weaving yarn 1 spool Passed manually through the shed
Loom components Manual shuttle Fabricated, purchased or improvised 1 Carries the weft yarn through the warp
Consumables 3D-printing filament PLA or equivalent As required Used to fabricate the printed structural components
Consumables Adhesive Hot glue, cyanoacrylate or equivalent As required Secures components where mechanical fastening is not used
Consumables Cable ties / fastening wire Small size As required Cable management and strain relief

Phase 2 — Additional Components Proposed

Category Component / Material Specification Quantity Purpose / Notes
Sensors Light-dependent resistors Standard LDR / photoresistor 8 Reads one punch-card position for each warp channel
Sensors Fixed resistors Value selected for LDR voltage dividers 8 Converts each LDR resistance into an analogue voltage
Lighting LED light sources White LEDs or LED strip 8 or 1 strip Illuminates the punch-card openings above the LDR array
Electronics Servo driver board PCA9685, 16-channel I²C 1 Optional expansion board for controlling multiple servos
Motion Stepper motor Size to be selected 1 Advances the punch-card strip
Motion Stepper motor driver Compatible with selected motor 1 Interfaces the stepper motor with the microcontroller
Mechanical Punch-card feed wheels 3D printed or laser cut 1 set Engages and advances the perforated pattern strip
Pattern medium Punch-card strip Paper, card or thin plastic sheet As required Stores linear or repeating weaving patterns

Video

Fabrication and Source Files

Phase 1 Files

  • 3D models
  • Laser-cut files
  • Arduino .ino file
  • p5.js pattern-generator files
  • Pattern image or sample file

Proposed Phase 2 Files

  • Punch-card layout
  • Card-reader design files
  • Feed-wheel design
  • Proposed circuit diagram
  • Proposed control-flow diagram

Arduino Loom

Concept

text

A mini-loom, expandable as needed. Servos control the heddles moving up and down; Arduino or othe uP controls the servos; Arduino gets input from either code or sensor; Sensor is LDR with Lightsource above; LDR is triggered by punch cards !

Punch card patterns -> read by LDR to Arduino -> which controls individual servos up or down

Shuttle is manual.

Punch card sheet like photography film, engaged in gear teeth, will move forward by a step using a stepper motor.

Punch card sheet can be manually filled or lasercut, linear or looping.

Kae Nagano's OS loom is a good reference for me, but I am also automating the heddles by using servo motors, and in phase 2 I want to add sensor input for the "punch card" patterns.

Analyses :

For 1 thread of warp :

  • 1 servo motor SG90
  • 1 LDR

Therefore for a 13+5=18 pin Arduino Uno, 8 warp threads = 8 servo signals + 8 LDR readings = 16 pins 1 signal to control stepper = 1 pin 1 signal to take input to move stepper and servos after shuttle has been shuttled

Additional uPs can be daisy chained, 8-9 threads per Arduino Uno since other boards can simply work in parallel, take I2C signal from mainboard.

Maybe try a Mega later ?

Get an I2C servo driver module ?

Trial

Tools

3D Models

Materials

Process

alt text

BoM

Bill of Materials

Arduino Loom — Current Prototype

Category Component / Material Specification Quantity Purpose / Notes
Electronics Arduino Uno ATmega328P development board 1 Controls the eight servo motors and reads the pushbutton input
Electronics Micro servo motors SG90, 9 g, 180° 8 One servo independently raises or lowers each warp thread
Electronics Momentary pushbutton Normally open tactile or panel-mount switch 1 Advances the loom to the next row of the programmed pattern
Electronics Jumper wires Male–male and/or male–female 1 set Connections between the Arduino, servos and pushbutton
Electronics Servo extension wires Three-core servo extensions, if required 8 Allows the servos to reach the controller without straining their leads
Electronics 5 V power supply Regulated supply, approximately 3 A 1 External power for the eight servos; the servo supply and Arduino must share a common ground
Electronics USB cable USB-A to USB-B 1 Programming and serial communication with the Arduino
Mechanical Servo horns Supplied with SG90 servos 8 Connect the servo shafts to the heddle or warp-control strings
Mechanical Servo mounting screws Supplied with the servos or equivalent 16 Two screws per servo for fixing the servos to the frame
Mechanical Laser-cut base and frame pieces Sheet material; type and thickness to be confirmed 1 set Holds and aligns the servos and loom mechanism
Mechanical 3D-printed mounting components PLA or equivalent filament 1 set Servo supports, rod holders, end brackets and connecting components
Mechanical Parallel rods / dowels Diameter and length to be measured from the prototype 2 Form the principal longitudinal structure of the loom
Mechanical General fasteners Nuts, bolts, washers and/or self-tapping screws 1 set Assembly of the frame and printed components; sizes to be confirmed
Loom components Warp-control cords Strong thread or fine cord 8 lengths Connect each servo horn to its corresponding warp thread or heddle
Loom components Warp yarn Suitable weaving yarn 8 ends minimum Eight independently controlled warp threads in the current prototype
Loom components Weft yarn Suitable weaving yarn 1 spool Passed manually through the shed
Loom components Manual shuttle Fabricated, purchased or improvised 1 Carries the weft yarn through the warp
Consumables 3D-printing filament PLA or equivalent As required Used to fabricate the printed structural components
Consumables Adhesive Hot glue, cyanoacrylate or equivalent As required Secures components where mechanical fastening is not used
Consumables Cable ties / fastening wire Small size As required Cable management and strain relief

Planned Punch-card Reader — Not Used in the Current Prototype

Category Component / Material Specification Quantity Purpose / Notes
Sensors Light-dependent resistors Standard LDR / photoresistor 8 Reads one punch-card position for each warp channel
Sensors Fixed resistors Value selected for LDR voltage dividers 8 Converts each LDR resistance into an analogue voltage
Lighting LED light sources White LEDs or LED strip 8 or 1 strip Illuminates the punch-card openings above the LDR array
Electronics Servo driver board PCA9685, 16-channel I²C 1 Optional expansion board for controlling multiple servos
Motion Stepper motor Size to be selected 1 Advances the punch-card strip
Motion Stepper motor driver Compatible with selected motor 1 Interfaces the stepper motor with the microcontroller
Mechanical Punch-card feed wheels 3D printed or laser cut 1 set Engages and advances the perforated pattern strip
Pattern medium Punch-card strip Paper, card or thin plastic sheet As required Stores linear or repeating weaving patterns

Code

Pattern Generator in p5.js

let weaveImage = "myImage.jpg"; 
let cols = 16;
let rows = 16;
let threshold = 128;

let img;
let weavePattern;

function preload() {
  img = loadImage(weaveImage);
}

function setup() {
  createCanvas(img.width, img.height);
  noLoop();

  // Make a copy and shrink it to grid size
  let small = img.get();   // copy to preserve original
  small.resize(cols, rows);  // resize image to grid

  // Generate 1/0 pattern
  small.loadPixels();
  weavePattern = [];

  for (let y = 0; y < rows; y++) {
    let row = [];
    for (let x = 0; x < cols; x++) {
      let idx = 4 * (y * small.width + x);
      let r = small.pixels[idx + 0];
      let g = small.pixels[idx + 1];
      let b = small.pixels[idx + 2];
      let bright = (r + g + b) / 3;
      row.push(bright < threshold ? 1 : 0);
    }
    weavePattern.push(row);
  }

  console.log("Weave pattern:", weavePattern);
  drawPixelated(weavePattern);
}

// Preview — unchanged
function drawPixelated(grid) {
  background(255);
  let cellW = width / cols;
  let cellH = height / rows;
  noStroke();
  for (let y = 0; y < rows; y++) {
    for (let x = 0; x < cols; x++) {
      fill(grid[y][x] === 1 ? 0 : 255);
      rect(x * cellW, y * cellH, cellW, cellH);
    }
  }
}

Arduino Code for loom

#include <Servo.h>

//  CONFIGURATION 
const byte NUM_SERVOS = 8;
const byte NUM_ROWS   = 8;  // number of rows in the pattern

// Pins for the 8 servos
const byte servoPins[NUM_SERVOS] = {3, 5, 6, 9, 10, 11, 12, 13};

// Button pin
const byte buttonPin = 2;  // wired to GND when pressed, with INPUT_PULLUP

// Servo angles
const int NEUTRAL_ANGLE = 90;
const int UP_ANGLE      = 180;  // 90° forward from neutral
const int DOWN_ANGLE    = 0;    // 90° backward from neutral

// Debounce
const unsigned long DEBOUNCE_MS = 50;

//  PATTERN (BINARY GRID) 
// 1 = move servo to UP_ANGLE
// 0 = move servo to DOWN_ANGLE
const byte weavePattern[NUM_ROWS][NUM_SERVOS] = {
  {0, 0, 0, 1, 1, 0, 0, 0},
  {0, 0, 1, 1, 1, 1, 0, 0},
  {0, 1, 1, 0, 0, 1, 1, 0},
  {1, 1, 0, 0, 0, 0, 1, 1},
  {1, 1, 0, 0, 0, 0, 1, 1},
  {0, 1, 1, 0, 0, 1, 1, 0},
  {0, 0, 1, 1, 1, 1, 0, 0},
  {0, 0, 0, 1, 1, 0, 0, 0}
};

//  GLOBALS 
Servo servos[NUM_SERVOS];

int currentRow = -1;            // starts at -1 so first tap moves to row 0
bool lastButtonState = HIGH;    // because of INPUT_PULLUP
unsigned long lastDebounceTime = 0;

//  SETUP 
void setup() {
  // Attach servos and move them to neutral
  for (byte i = 0; i < NUM_SERVOS; i++) {
    servos[i].attach(servoPins[i]);
    servos[i].write(NEUTRAL_ANGLE);
  }

  // Button with internal pullup
  pinMode(buttonPin, INPUT_PULLUP);

  // Optional: for debugging over serial
  Serial.begin(9600);
  Serial.println("Servo weave pattern ready. Tap switch to step rows.");
}

//  LOOP 
void loop() {
  // Read the button
  bool reading = digitalRead(buttonPin);

  // Debounce logic
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > DEBOUNCE_MS) {
    static bool lastStableState = HIGH;
    if (reading != lastStableState) {
      lastStableState = reading;

      if (reading == LOW) {
        advanceRowAndMoveServos();
      }
    }
  }

  lastButtonState = reading;
}

//  FUNCTIONS 

// Advance to the next row of the binary grid and move all 8 servos
void advanceRowAndMoveServos() {
  // Move to next row (wrap around)
  currentRow = (currentRow + 1) % NUM_ROWS;

  Serial.print("Moving to row ");
  Serial.println(currentRow);

  // For each servo/column in this row:
  for (byte col = 0; col < NUM_SERVOS; col++) {
    byte bit = weavePattern[currentRow][col];

    int targetAngle;
    if (bit == 1) {
      targetAngle = UP_ANGLE;
    } else {
      targetAngle = DOWN_ANGLE;
    }

    servos[col].write(targetAngle);
  }

  delay(20);
}

Video

Fabrication files