Skip to main content

Circular Servo Motor Array with Arduino Mega 2560 – Kinetic Art & Robotic Display System (Wokwi Simulation)

Kinetic Mandala: 32 Servo Motors with Arduino Mega 2560 | MakeMindz
Advanced Arduino Mega 2560 Wokwi Simulation 32 Servos

Kinetic Mandala — Circular Servo Array Using Arduino Mega 2560

Control 32 servo motors arranged in a perfect radial pattern from a single Arduino Mega. Create wave animations, compass sweeps, and synchronized kinetic art. Fully simulated in Wokwi — no hardware needed to start.

🕒 ~45 min build ⚡ 15–25A power supply 🔧 Pins 22–53 📡 PWM · Servo.h
ARDUINO MEGA 2560

32 SG90 servo motors arranged in a perfect radial pattern, individually controlled via PWM pins 22–53

🎯 Project Overview

The Circular Servo Motor Array uses 32 SG90-type micro servo motors arranged in a perfect circle, each controlled individually by the Arduino Mega 2560's digital I/O pins 22–53. Designed and simulated in Wokwi, this project is ideal for kinetic sculptures, mechanical displays, and interactive art systems.

SEQUENCE 01
Random Angles
All 32 servos jump to random positions, creating chaotic organic motion repeated 15 times.
SEQUENCE 02
Synchronized Sweep
All motors move together 0°→180°→0° in unison — a perfect unified sweep, 3 repetitions.
SEQUENCE 03
Rotating Wave
A ripple effect travels around the ring using circular distance math — 6 full rotations.
SEQUENCE 04
Compass Pointer
Two servos form a pointer; opposite servos form a tail. Simulates a compass needle swinging.

🔩 Hardware Components

Arduino Mega 2560
×1 — main controller
Micro Servo (SG90)
×32 — 180° rotation
5V Power Supply
High-current, 20A+
Power Distribution Bus
Shared V+ and GND rails
Common Ground Wiring
Arduino GND to PSU GND
Jumper Wires
×96+ (3 per servo)
;">

🔌 Wiring Guide

Each servo has 3 wires. Connect them as follows — repeat for all 32 servos:

Servo Wire Colour Connect To Notes
Signal (PWM) Orange/Yellow Arduino pin 22–53 (servo 0–31) Servo 0 → Pin 22, Servo 1 → Pin 23 …
Power (V+) Red External 5V Power Rail Never use Arduino 5V for all 32
Ground Brown/Black Common GND rail Connect to both PSU GND and Arduino GND
⚠️
Critical Wiring Rule
Always connect the Arduino GND to the external power supply GND. Without a common ground, the PWM signals will not work correctly and servos may jitter or fail.
ℹ️
Chain Power for Simulation
In the Wokwi simulation, V+ and GND are chained between adjacent servos (servo0 → servo1 → servo2 …) forming a ring. In real hardware, use a proper power distribution bus bar instead.

📐 Step-by-Step Instructions

01
Open Wokwi and Start a New Project
Go to wokwi.com and create a new Arduino Mega 2560 project. Alternatively, click the Free Simulation button at the top of this page to open the ready-made project directly.
02
Load the diagram.json
In your Wokwi project, click the diagram.json tab and replace the entire contents with the JSON provided in the Diagram JSON section below. This will place all 32 servos in their correct radial positions and wire their PWM signals to pins 22–53.
💡
Auto-Generate (Optional)
The GenerateDiagram() function in the sketch can regenerate this JSON fresh via Serial output — call it from setup() and copy the Serial Monitor output.
03
Paste the Arduino Sketch
Click the sketch.ino tab in Wokwi and paste the full code from the Arduino Code section below. The sketch defines:
  • NUM_SERVOS 32 — number of motors
  • Servo myServo[NUM_SERVOS] — servo array
  • Attach loop using pins 22–53 in setup()
  • 4 motion sequences in loop()
04
Run the Simulation
Press the ▶ Play button in Wokwi. The simulation will start and you'll see the 32 servo horns animated in the circular arrangement. Watch all 4 sequences cycle automatically:
  • Random chaos (15× repetitions)
  • Unified sweep 0°↔180° (3× repetitions)
  • Rotating wave effect (6× repetitions)
  • Compass pointer animation
05
Real Hardware Build (Optional)
For a physical build:
  • Mount 32 SG90 servos in a circular frame (laser-cut acrylic or 3D-printed ring works well)
  • Connect each PWM signal wire to Arduino pin i + 22
  • Route all V+ wires to a power distribution bus connected to an external 5V / 20A+ supply
  • Connect all GND wires together and to the Arduino GND
  • Upload the sketch via USB using the Arduino IDE
⚠️
Never Power from Arduino
The Arduino 5V pin can only supply ~500mA total. Powering 32 servos from it will damage your board.
06
Customise the Motion
Experiment with the code to create your own patterns:
  • Change NUM_SERVOS to 16, 24, or 40 (adjust diagram.json accordingly)
  • Adjust wave speed by changing the delay(40) in Sequence 3
  • Modify the angle formula 90 - (10 * d) to control wave steepness
  • Add a sine wave pattern using sin() from math.h

🎮 Try It Free in Your Browser

No hardware needed — run the full 32-servo simulation instantly in Wokwi. Watch all 4 motion sequences live.

Launch Free Simulation on Wokwi

🌊 Motion Sequences — How They Work

The loop() function cycles through 4 sequences automatically. Here's the maths behind each one:

Sequence 1 — Random Angles

Calls random(0, 181) for each servo. 15 rounds, with a 150ms pause between each. Simple but visually striking — useful for "alive" organic art effects.

Sequence 2 — Synchronized Sweep

Increments a shared angle r from 0→180 then 180→0, writing it to all 32 servos simultaneously. 6ms delay per degree = a smooth, unified sweep.

Sequence 3 — Rotating Wave

For each "active" servo i, each other servo j gets an angle based on its circular distance: angle = 90 - (10 × d) where d uses modular arithmetic to wrap around the ring. Creates a smooth ripple.

Sequence 4 — Compass Pointer

The showPointer(s) function uses the % (modulo) operator to wrap servo indices. Servo s and s+1 form the pointer tip; s+16 and s+17 (opposite side) form the tail. All others lay flat.

💻 Arduino Code (sketch.ino)

Copy this complete sketch into your Wokwi sketch.ino tab or the Arduino IDE:

Arduino C++ · sketch.ino
// ServoOverdone.ino
// Circular servo motor array — 32 SG90 servos on Arduino Mega 2560
// Version 2, August 2021 — Public Domain

#include <Servo.h>

#define NUM_SERVOS 32
Servo myServo[NUM_SERVOS];

void setup()
{
  // Attach pins 22–53 to servo objects (32 pins)
  for( int i=0; i<NUM_SERVOS; i++)
  {
    myServo[i].attach( i + 22);
  }
}

void loop()
{
  // ── Sequence 1: Random angles (15 rounds) ──
  for( int a=0; a<15; a++)
  {
    for( int i=0; i<NUM_SERVOS; i++)
    {
      myServo[i].write( random( 0, 181));
      delay( 2);
    }
    delay( 150);
  }

  // ── Sequence 2: Synchronized sweep 0°↔180° (3 repetitions) ──
  for( int i=0; i<NUM_SERVOS; i++)
    myServo[i].write( 0);
  delay( 1000);

  for( int a=0; a<3; a++)
  {
    for( int r=0; r<=180; r++)      // sweep right
    {
      for( int i=0; i<NUM_SERVOS; i++)
        myServo[i].write( r);
      delay( 6);
    }
    for( int r=180; r>=0; r--)      // sweep left
    {
      for( int i=0; i<NUM_SERVOS; i++)
        myServo[i].write( r);
      delay( 6);
    }
  }

  // ── Sequence 3: Rotating wave (6 full rotations) ──
  for( int a=0; a<6; a++)
  {
    for( int i=0; i<NUM_SERVOS; i++)
    {
      for( int j=0; j<NUM_SERVOS; j++)
      {
        int d = j - i;
        if( d < 0) d = -d;
        if( d > (NUM_SERVOS / 2)) d = NUM_SERVOS - d;

        int angle = 90 - (10 * d);
        if( angle < 0) angle = 0;
        myServo[j].write( angle);
      }
      delay(40);
    }
  }

  // ── Sequence 4: Compass pointer ──
  int pointer = NUM_SERVOS * 3 / 4;  // start pointing up
  showPointer( pointer);
  delay( 1000);

  for( int i=0; i<5; i++) { showPointer( --pointer); delay(150); }
  delay(200);
  for( int i=0; i<9; i++) { showPointer( ++pointer); delay(150); }
  delay(200);
  for( int i=0; i<5; i++) { showPointer( --pointer); delay(150); }
  delay(200);
  for( int i=0; i<4; i++) { showPointer( ++pointer); delay(150); }
  delay(160);
  for( int i=0; i<2; i++) { showPointer( --pointer); delay(150); }
  delay(80);
  showPointer( ++pointer);
  delay(2000);
}

// Creates a compass pointer using servo at position 's'
// Uses modulo (%) to wrap around the circular array
void showPointer( int s)
{
  int pointerA = s % NUM_SERVOS;
  int pointerB = (s + 1) % NUM_SERVOS;
  int tailA    = (s + 16) % NUM_SERVOS;
  int tailB    = (s + 17) % NUM_SERVOS;

  myServo[pointerA].write(180-56);  // = 124°
  myServo[pointerB].write(56);

  myServo[tailA].write(95);
  myServo[tailB].write(85);

  int n = (NUM_SERVOS / 2) - 2;

  int start = pointerB + 1;
  for( int i=0; i<n; i++)
    myServo[(start + i) % NUM_SERVOS].write( 2);

  start = tailB + 1;
  for( int i=0; i<n; i++)
    myServo[(start + i) % NUM_SERVOS].write( 178);
}

📄 diagram.json — Wokwi Layout

Paste this into the diagram.json tab in Wokwi. It places all 32 servos in a perfect radial circle around the Arduino Mega, with red horn colours:

JSON · diagram.json
{
  "version": 1,
  "author": "Generated",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-arduino-mega", "id": "mega", "top": 270, "left": 185, "attrs": {} },
    { "type": "wokwi-servo", "id": "servo31", "top": 241.47, "left": 594.24, "rotate": 348.75, "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo30", "top": 185.19, "left": 577.16, "rotate": 337.5,  "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo29", "top": 133.33, "left": 549.44, "rotate": 326.25, "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo28", "top": 87.87,  "left": 512.13, "rotate": 315,    "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo27", "top": 50.56,  "left": 466.67, "rotate": 303.75, "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo26", "top": 22.84,  "left": 414.81, "rotate": 292.5,  "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo25", "top": 5.76,   "left": 358.53, "rotate": 281.25, "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo24", "top": 0,      "left": 300,    "rotate": 270,    "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo23", "top": 5.76,   "left": 241.47, "rotate": 258.75, "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo22", "top": 22.84,  "left": 185.2,  "rotate": 247.5,  "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo21", "top": 50.56,  "left": 133.33, "rotate": 236.25, "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo20", "top": 87.87,  "left": 87.87,  "rotate": 225,    "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo19", "top": 133.33, "left": 50.56,  "rotate": 213.75, "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo18", "top": 185.19, "left": 22.84,  "rotate": 202.5,  "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo17", "top": 241.47, "left": 5.76,   "rotate": 191.25, "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo16", "top": 300,    "left": 0,      "rotate": 180,    "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo15", "top": 358.53, "left": 5.76,   "rotate": 168.75, "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo14", "top": 414.8,  "left": 22.84,  "rotate": 157.5,  "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo13", "top": 466.67, "left": 50.56,  "rotate": 146.25, "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo12", "top": 512.13, "left": 87.87,  "rotate": 135,    "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo11", "top": 549.44, "left": 133.33, "rotate": 123.75, "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo10", "top": 577.16, "left": 185.19, "rotate": 112.5,  "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo9",  "top": 594.24, "left": 241.47, "rotate": 101.25, "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo8",  "top": 600,    "left": 300,    "rotate": 90,     "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo7",  "top": 594.24, "left": 358.53, "rotate": 78.75,  "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo6",  "top": 577.16, "left": 414.81, "rotate": 67.5,   "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo5",  "top": 549.44, "left": 466.67, "rotate": 56.25,  "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo4",  "top": 512.13, "left": 512.13, "rotate": 45,     "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo3",  "top": 466.67, "left": 549.44, "rotate": 33.75,  "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo2",  "top": 414.81, "left": 577.16, "rotate": 22.5,   "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo1",  "top": 358.53, "left": 594.24, "rotate": 11.25,  "attrs": { "hornColor": "Red" } },
    { "type": "wokwi-servo", "id": "servo0",  "top": 300,    "left": 600,                    "attrs": { "hornColor": "Red" } }
  ],
  "connections": [
    [ "servo0:V+",   "servo1:V+",   "Red",   [] ], [ "servo0:GND",  "servo1:GND",  "Black", [] ], [ "mega:22",  "servo0:PWM",  "Green", [] ],
    [ "servo1:V+",   "servo2:V+",   "Red",   [] ], [ "servo1:GND",  "servo2:GND",  "Black", [] ], [ "mega:23",  "servo1:PWM",  "Green", [] ],
    [ "servo2:V+",   "servo3:V+",   "Red",   [] ], [ "servo2:GND",  "servo3:GND",  "Black", [] ], [ "mega:24",  "servo2:PWM",  "Green", [] ],
    [ "servo3:V+",   "servo4:V+",   "Red",   [] ], [ "servo3:GND",  "servo4:GND",  "Black", [] ], [ "mega:25",  "servo3:PWM",  "Green", [] ],
    [ "servo4:V+",   "servo5:V+",   "Red",   [] ], [ "servo4:GND",  "servo5:GND",  "Black", [] ], [ "mega:26",  "servo4:PWM",  "Green", [] ],
    [ "servo5:V+",   "servo6:V+",   "Red",   [] ], [ "servo5:GND",  "servo6:GND",  "Black", [] ], [ "mega:27",  "servo5:PWM",  "Green", [] ],
    [ "servo6:V+",   "servo7:V+",   "Red",   [] ], [ "servo6:GND",  "servo7:GND",  "Black", [] ], [ "mega:28",  "servo6:PWM",  "Green", [] ],
    [ "servo7:V+",   "servo8:V+",   "Red",   [] ], [ "servo7:GND",  "servo8:GND",  "Black", [] ], [ "mega:29",  "servo7:PWM",  "Green", [] ],
    [ "servo8:V+",   "servo9:V+",   "Red",   [] ], [ "servo8:GND",  "servo9:GND",  "Black", [] ], [ "mega:30",  "servo8:PWM",  "Green", [] ],
    [ "servo9:V+",   "servo10:V+",  "Red",   [] ], [ "servo9:GND",  "servo10:GND", "Black", [] ], [ "mega:31",  "servo9:PWM",  "Green", [] ],
    [ "servo10:V+",  "servo11:V+",  "Red",   [] ], [ "servo10:GND", "servo11:GND", "Black", [] ], [ "mega:32",  "servo10:PWM", "Green", [] ],
    [ "servo11:V+",  "servo12:V+",  "Red",   [] ], [ "servo11:GND", "servo12:GND", "Black", [] ], [ "mega:33",  "servo11:PWM", "Green", [] ],
    [ "servo12:V+",  "servo13:V+",  "Red",   [] ], [ "servo12:GND", "servo13:GND", "Black", [] ], [ "mega:34",  "servo12:PWM", "Green", [] ],
    [ "servo13:V+",  "servo14:V+",  "Red",   [] ], [ "servo13:GND", "servo14:GND", "Black", [] ], [ "mega:35",  "servo13:PWM", "Green", [] ],
    [ "servo14:V+",  "servo15:V+",  "Red",   [] ], [ "servo14:GND", "servo15:GND", "Black", [] ], [ "mega:36",  "servo14:PWM", "Green", [] ],
    [ "servo15:V+",  "servo16:V+",  "Red",   [] ], [ "servo15:GND", "servo16:GND", "Black", [] ], [ "mega:37",  "servo15:PWM", "Green", [] ],
    [ "servo16:V+",  "servo17:V+",  "Red",   [] ], [ "servo16:GND", "servo17:GND", "Black", [] ], [ "mega:38",  "servo16:PWM", "Green", [] ],
    [ "servo17:V+",  "servo18:V+",  "Red",   [] ], [ "servo17:GND", "servo18:GND", "Black", [] ], [ "mega:39",  "servo17:PWM", "Green", [] ],
    [ "servo18:V+",  "servo19:V+",  "Red",   [] ], [ "servo18:GND", "servo19:GND", "Black", [] ], [ "mega:40",  "servo18:PWM", "Green", [] ],
    [ "servo19:V+",  "servo20:V+",  "Red",   [] ], [ "servo19:GND", "servo20:GND", "Black", [] ], [ "mega:41",  "servo19:PWM", "Green", [] ],
    [ "servo20:V+",  "servo21:V+",  "Red",   [] ], [ "servo20:GND", "servo21:GND", "Black", [] ], [ "mega:42",  "servo20:PWM", "Green", [] ],
    [ "servo21:V+",  "servo22:V+",  "Red",   [] ], [ "servo21:GND", "servo22:GND", "Black", [] ], [ "mega:43",  "servo21:PWM", "Green", [] ],
    [ "servo22:V+",  "servo23:V+",  "Red",   [] ], [ "servo22:GND", "servo23:GND", "Black", [] ], [ "mega:44",  "servo22:PWM", "Green", [] ],
    [ "servo23:V+",  "servo24:V+",  "Red",   [] ], [ "servo23:GND", "servo24:GND", "Black", [] ], [ "mega:45",  "servo23:PWM", "Green", [] ],
    [ "servo24:V+",  "servo25:V+",  "Red",   [] ], [ "servo24:GND", "servo25:GND", "Black", [] ], [ "mega:46",  "servo24:PWM", "Green", [] ],
    [ "servo25:V+",  "servo26:V+",  "Red",   [] ], [ "servo25:GND", "servo26:GND", "Black", [] ], [ "mega:47",  "servo25:PWM", "Green", [] ],
    [ "servo26:V+",  "servo27:V+",  "Red",   [] ], [ "servo26:GND", "servo27:GND", "Black", [] ], [ "mega:48",  "servo26:PWM", "Green", [] ],
    [ "servo27:V+",  "servo28:V+",  "Red",   [] ], [ "servo27:GND", "servo28:GND", "Black", [] ], [ "mega:49",  "servo27:PWM", "Green", [] ],
    [ "servo28:V+",  "servo29:V+",  "Red",   [] ], [ "servo28:GND", "servo29:GND", "Black", [] ], [ "mega:50",  "servo28:PWM", "Green", [] ],
    [ "servo29:V+",  "servo30:V+",  "Red",   [] ], [ "servo29:GND", "servo30:GND", "Black", [] ], [ "mega:51",  "servo29:PWM", "Green", [] ],
    [ "servo30:V+",  "servo31:V+",  "Red",   [] ], [ "servo30:GND", "servo31:GND", "Black", [] ], [ "mega:52",  "servo30:PWM", "Green", [] ],
    [ "servo31:V+",  "servo0:V+",   "Red",   [] ], [ "servo31:GND", "servo0:GND",  "Black", [] ], [ "mega:53",  "servo31:PWM", "Green", [] ],
    [ "mega:GND.2", "servo9:GND", "Black", [] ],
    [ "mega:5V",    "servo9:V+",  "Red",   [] ]
  ],
  "dependencies": {}
}

Power Planning

32 servos demand serious current. Here's the calculation:

SG90 stall current (peak) ~1A per servo
SG90 running current (typical) ~500mA per servo
32 servos × 500mA (typical) 16A minimum
32 servos × 1A (peak stall) 32A peak max
Recommended PSU 5V / 20–30A
⚠️
Never power servos from the Arduino
The Arduino Mega's 5V pin is regulated for ~500mA total. Connecting even 2–3 servos to it under load will cause brown-outs and board damage. Always use a dedicated external power supply.
💡
Tip: Stagger servo movements
In your custom code, avoid commanding all 32 servos to stall simultaneously. Staggering movement reduces peak current draw significantly.

🚀 Possible Applications

🎨 Kinetic Art Installation
Mechanical Clock Display
🌊 Ripple Wave Sculpture
🧭 Servo-Based Compass
🤖 Robotic Base Platform
📺 Mechanical Pixel Display
🎓 Educational Demo
🌀 Mandala Art Piece

🎓 What You Will Learn

Multi-servo array programming
PWM control on Arduino Mega
Circular motion mathematics
Modular arithmetic for rotation
High-current power distribution
Large system simulation in Wokwi
Structured embedded system design
Auto-generated hardware layouts

Ready to Build? Start with the Free Simulation

All 32 servos, all 4 motion sequences, live in your browser — no components, no soldering required.

Open Free Simulation →

© 2026 MakeMindz.com — Arduino, Wokwi & Embedded Systems Tutorials

Code originally by Koepel — Public Domain · Tutorial page for educational use

Comments

try for free