Cells breathe, ripple, and react — proximity in, synchronized motion and light out.
Built by Team Pulse — 🎖️ Honorable Mention, Maker Yarışması 2026 (Özyeğin University)
Team Pulse, building and testing HexCells at the OpenFab workspace, Özyeğin University.
- About the Project
- How It Works
- Project Status
- Features
- Hardware
- Wiring
- Software
- Repository Structure
- Getting Started
- The Modes
- Calibration
- Design & Fabrication
- Simulation
- Power Requirements
- Future Work
- Gallery
- Team
- Acknowledgments
- License
HexCells is an installation of hexagonal cells arranged in a geometric pattern. Ultrasonic sensors detect people approaching the wall, and in response the individual cells extrude mechanically — via 3D-printed rack-and-pinion mechanisms driven by continuous-rotation servos — while addressable RGB LEDs light them up in synchronized patterns.
The result is a wall that:
- Reacts to human presence in real time
- Displays organic, wave-like movement across its cells
- Cycles through 12 animated light-and-motion modes
- Feels alive and aware
The prototype is a 6-cell ring with cells arranged in a circle around an empty center. The finalized full-scale design is intended to be 73 cells.
hex33.mp4
flowchart LR
Person(("Person\napproaching")) -- distance --> S1["HC-SR04\nSensor 1"]
Person -- distance --> S2["HC-SR04\nSensor 2"]
Person -- distance --> S3["HC-SR04\nSensor 3"]
subgraph Wall["⬡ Hex-Wall (6-cell ring)"]
MCU["Arduino Mega 2560"]
SERVO["6× SG90 Servos\n(rack & pinion extrusion)"]
LED["6× WS2812 RGB LEDs"]
OLED["SSD1306 OLED\n(current mode)"]
BTN["Mode button"]
end
S1 --> MCU
S2 --> MCU
S3 --> MCU
BTN -- "cycle 12 modes" --> MCU
MCU -- "extrude / retract" --> SERVO
MCU -- "hue + brightness" --> LED
MCU -- "mode name" --> OLED
Loading
Three ultrasonic sensors continuously measure distance to whoever is nearby. Each cell's target extrusion is computed from a k-nearest-sensor interpolation — the closer sensor(s) dominate a cell's response, so proximity near one side of the ring smoothly influences neighboring cells too, rather than each cell reacting only to its own dedicated sensor. The same Arduino Mega drives all 6 servos (motion) and all 6 WS2812 LEDs (light) every frame, so the two are always in sync.
A physical button cycles through 12 modes — one fully interactive (proximity-driven) and eleven pre-animated (wave, breath, sparkle, fire, rainbow, and more). Every mode change homes all servos back to a clean starting position first.
- ✅ 6-cell physical prototype built and tested
- ✅ All 12 modes running (Interact, Wave, Breath, Sparkle, Counter, RevCount, Comet, Fire, Rainbow, Pendulum, Fill, Park)
- ✅ Homing on power-up and mode change
- ✅ Servo and LED calibration remaps in place
- ✅ Python simulator built for pre-hardware design work
- ⏳ Scaling to 73 cells (future work)
- 🐝 Ring of 6 extruding hexagonal cells, each independently driven by its own servo and LED
- 🎯 Proximity-driven interaction — k-nearest-sensor interpolation blends input from 3 sensors across all 6 cells
- 🌈 12 animated modes — from a slow ambient breathing pattern to a flickering fire effect to a full rotating rainbow
- 🖥️ Live OLED status display — shows the current mode, cycled with a single button
- 🧭 Software-corrected wiring — servo and LED chain-order mismatches from the physical build are fixed entirely in code, no rewiring needed
- 🧪 Pre-hardware Python simulator — the animation modes were designed and tested in simulation before ever touching a servo
🅿️ Safe-shutdown Park mode — detaches all servos and shows "safe to power off" on the OLED
(× 6 unless noted — one set per cell)
| Component | Quantity | Notes |
|---|---|---|
| Arduino Mega 2560 R3 | 1 | Main controller |
| SG90 Continuous-Rotation Servo | 6 | One per cell, drives extrusion |
| HC-SR04 Ultrasonic Sensor | 3 | 4-pin: VCC, TRIG, ECHO, GND |
| WS2812 8mm Addressable RGB LED | 6 | One per cell, daisy-chained |
| 0.96" I2C SSD1306 OLED (128×64) | 1 | Displays current mode |
| Push button | 1 | Cycles modes |
| 470µF / 16V electrolytic capacitor | 2 | Power smoothing |
| 0.1µF (100 nF) ceramic capacitor | 10 | Signal decoupling |
| 470Ω resistor | 1 | LED data line |
| Breadboards (large) | 2 | Wiring |
| Jumper wires | many | Wiring |
| Material | Purpose |
|---|---|
| 3mm MDF (laser-cut) | Cell walls |
| Transparent 3D-printed filament (Ultrafuse Clear) | Cell top covers for light transmission |
| 3D-printed PLA | Rack-and-pinion mechanisms |
| Cardboard | Outer shell / concealment of electronics |
An external 5V 5A power supply is required for reliable operation of all six servos together. The Arduino's USB or DC jack alone cannot supply the ~4A peak current the servos draw. See Power Requirements.
Full pin-by-pin tables are in
docs/wiring/WIRING.md.
Key design notes:
- Servos on pins 2–7, LED data on pin 8, button on pin 30, sensors on 22/23, 24/25, and 26/27, OLED on the I2C bus (SDA=20, SCL=21).
- Cells 5 and 6 are physically wired to swapped servo pins — corrected entirely in software (
SERVO_PINS[]), no rewiring needed. - The WS2812 LED chain isn't wired in cell order either — corrected via
LED_MAP[]. See Calibration.
Install via Arduino IDE Library Manager (Sketch → Include Library → Manage Libraries):
- FastLED by Daniel Garcia
- Adafruit SSD1306 by Adafruit
- Adafruit GFX Library by Adafruit
- (Adafruit BusIO — installed automatically as a dependency)
The Servo and Wire libraries come built-in with the Arduino IDE.
The Python simulator (simulator/app.py) needs pygame:
pip install pygame| File | Purpose |
|---|---|
firmware/HexWall_Controller_ring_final.ino |
Main sketch — full 12-mode controller |
firmware/HexWall_Calibration_All.ino |
Combined menu-driven calibration test (servos, LEDs, sensors, button) |
simulator/app.py |
Python simulator used for pre-hardware design |
simulator/hex_font.py |
Dot-matrix font module used by the simulator for hex-grid text rendering |
hex-wall/
├── README.md this file
├── LICENSE
├── firmware/
│ ├── HexWall_Controller_ring_final.ino main sketch (12 modes)
│ └── HexWall_Calibration_All.ino combined calibration test
├── simulator/
│ ├── app.py Python design/simulation tool
│ └── hex_font.py dot-matrix font used for hex-grid text display in the simulator
├── cad/
│ ├── Final6cells.dxf laser-cut file for the 6-cell prototype
│ └── Final6cells.svg same design, SVG source
└── docs/
├── report.pdf Maker Yarışması 2026 project report (Team Pulse, Group 3)
├── wiring/
│ └── WIRING.md full pin-by-pin wiring reference
└── media/ logos, team photo, and build photos
Note: There's currently no separate Fusion 360 (
.f3d) source file or standalone STL files in this repo — only the laser-cut DXF/SVG for the 6-cell prototype. The rack-and-pinion and cover geometry described above exists in the physical build and the Fusion 360 project, but hasn't been exported/added here yet.
- Install the Arduino IDE (1.8.19 or 2.x)
- Install to a folder path with NO spaces (e.g.
C:\Arduino\, notC:\Program Files\...with spaces). Spaces in the path can cause linker errors likeundefined reference to main.
Open Sketch → Include Library → Manage Libraries and install FastLED, Adafruit SSD1306, and Adafruit GFX (see Software).
Save HexWall_Controller_ring_final.ino in a folder path without spaces (e.g. C:\ArduinoSketches\HexWall\).
Tools → Board → Arduino Mega or Mega 2560 → ATmega2560 (Mega 2560).
Tools → Port → whichever COM port your Arduino is on.
Click the Upload button (arrow icon). Watch the bottom of the IDE for "Done uploading."
Connect the external 5V supply to the breadboard rails. The Arduino can be powered via USB or the DC jack (7–12V). Make sure Arduino GND is connected to the breadboard GND rail — shared ground is essential.
The system will home all servos to the start position on power-up.
The button (pin 30) cycles through 12 modes. The current mode is shown on the OLED. Every mode change first homes all servos back to 0° for a clean start.
| # | Mode | Description |
|---|---|---|
| 1 | Interact | Sensors drive the cells: the closer someone is, the more that cell (and its ring neighbors) extend. Uses distance-based interpolation. |
| 2 | Wave | A sinusoidal wave sweeps around the ring, colors cycling through the spectrum. |
| 3 | Breath | All cells rise and fall together at a slow, meditative pace in warm amber. |
| 4 | Sparkle | Random cells pop up bright with vivid random colors and fade out. Gaps between sparkles are randomized (0.6–2.2 seconds by default). |
| 5 | Counter | Stepped chase around the ring with a fading trail, in green. |
| 6 | RevCount | Same stepped chase, but sweeps one way then reverses. Green forward, orange back. |
| 7 | Comet | A smooth bright head races around the ring leaving a fading tail. Head color drifts each lap. |
| 8 | Fire | Flickering flame effect. Flame color oscillates slowly through warm red → green → blue → back. |
| 9 | Rainbow | Full rainbow spread around the ring, rotating continuously. |
| 10 | Pendulum | Smooth comet that sweeps one way, eases to a stop, then reverses. |
| 11 | Fill | Cells fill up one by one around the ring (warm gold), then empty back out (cool blue). |
| 12 | Park | All motors home and detach for safe shutdown. OLED shows "PARKED — Safe to power off." |
Key values at the top of the sketch:
int K_NEAREST = 2; // sensor interpolation spread (1-2)
const int DETECT_THRESHOLD_CM = 40; // proximity trigger distance
const int BRIGHTNESS = 150; // LED master brightness (0-255)
const float SMOOTH = 0.18; // servo motion smoothing (lower = smoother)Per-mode tunables include Sparkle spawn intervals (SPARKLE_MIN_GAP, SPARKLE_MAX_GAP) and Fire color speed (FIRE_COLOR_SPEED).
Because breadboard wiring rarely follows perfect index order, the code includes two software remaps so no rewiring is needed when servos or LEDs come out physically scrambled:
// cell: 1 2 3 4 5 6
const int SERVO_PINS[6] = { 2, 3, 4, 5, 7, 6};Pins 6 and 7 are swapped in the array because cells 5 and 6 were physically wired to the "wrong" pins. The remap fixes it entirely in software.
// Chain order found by testing: cell 1, 4, 5, 6, 3, 2.
// cell: 1 2 3 4 5 6
const int LED_MAP[6] = { 0, 5, 4, 1, 2, 3};LED_MAP[cell] gives the position in the WS2812 chain for that cell.
If you rebuild the wiring, use firmware/HexWall_Calibration_All.ino. Upload it, open the Serial Monitor (9600 baud, Newline line-ending), and choose a test from the menu:
- S — servo test: type 1–6 to sweep each servo, note which physical cell moves
- L — LED test: type 1–6 to light each LED white, note which physical cell lights up
- U — sensor test: live readings from all 3 sensors
- B — button test: counts presses
Use the servo and LED results to update SERVO_PINS[] and LED_MAP[] in the main sketch.
Each cell is a hexagonal enclosure with:
- 3mm MDF walls — laser-cut with finger joints
- 3D-printed top cover (transparent filament, 4mm thick, 0.18mm layer height, 70% infill) for light transmission
- 3D-printed rack-and-pinion mechanism driven by an SG90 servo
- Sensor-variant covers include two Ø17mm holes (26mm center-to-center) for the HC-SR04 face
- Power: ~60–70%
- Speed: 25–35 mm/s
- Air assist: on
- Cut inner features first
- Filament: Ultrafuse transparent for covers
- Temperature: 210°C
- Layer height: 0.18 mm
- Infill: 70%
- No supports; smooth side down on the bed
Prior to any hardware, a Python simulator was built to prototype the design end-to-end. The simulator (simulator/app.py) models:
- The full hexagonal grid at any scale (6-cell prototype up to 73-cell full design)
- Configurable sensor placement
- Proximity-based cell extrusion with
k_nearestinterpolation between sensors - All animation modes (Interact, Wave, Breath, Sparkle, etc.)
- Real-time visualization of the wall's behavior
The animation modes developed in the simulator were carried directly into the Arduino code, so the physical wall behaves the same as the simulator predicted.
- Six SG90 servos moving together draw up to ~4A peak
- Six WS2812 LEDs at full white draw up to ~360mA
- OLED + sensors + button ≈ 65mA
- Total peak: ~4.4A
The Arduino Mega's onboard 5V regulator supplies only ~500mA. The DC jack does not change this — it only powers the Arduino chip itself, not peripherals.
A 5V DC, 5A dedicated power adapter, wired directly to the breadboard rails:
5V/5A supply ─→ Breadboard +5V rail → all servo VCC + all LED VCC
─→ Breadboard GND rail → all servo GND + all LED GND
→ Arduino GND (shared ground — essential)
Arduino ─→ USB or DC jack for its own power
─→ Do NOT connect Arduino 5V pin to the external supply
Single-servo tests (like the calibration sketch) work on USB power because only one servo moves at a time. All-servo modes (Wave, Breath, Ripple, etc.) will brown out the Arduino on USB.
A 7.4V 2S LiPo can power the system if paired with a 5A step-down (buck) converter set to output 5V. LiPo safety practices apply — never over-discharge (below 6.0V total), use a proper balance charger, and add a fuse.
- Scaling to 73 cells is the main piece of future work — the current build proves the concept and the interaction model at 6 cells around a ring; the finalized design calls for a much larger grid, which will need a rethink of wiring topology (daisy-chaining 73 LEDs and servos isn't the same problem as 6) and likely a move off a single Arduino Mega.
- Adding the CAD source files — a Fusion 360 (
.f3d) source and standalone STL exports, so the full cell geometry is reproducible from this repo, not just the laser-cut DXF/SVG.
Simulated preview of the finalized 73-cell design, built in the same Python simulator used for the 6-cell prototype.
hex1.mp4
hex22.mp4
Team Pulse
| 👤 Amr Genidy | @AmrGenidy |
| 👤 Hamza Yüksel | @yukselh20 |
🎖️ Honorable Mention — Maker Yarışması 2026, hosted at Özyeğin University's OpenFab.
- Özyeğin University and OpenFab for the workspace, tools, and support throughout the build.
This project is licensed under the MIT License.
Built with ultrasonic sensors, servo motors, and a lot of iteration.









