1 / 4
Large Modular 3D Scanning Turntable – ESP32 — zdjęcie 1
1 / 4

Large Modular 3D Scanning Turntable – ESP32

Zamów wydruk tego modelu

Obliczymy ostateczną cenę na podstawie wybranego pliku. Sprawdzisz ją i zaakceptujesz przed płatnością.

Zapisane na tym urządzeniu.

A large, modular motorized turntable designed for 3D scanning and product display. Powered by an 28BYJ-48

Ocena
0 / 5
Polubienia
3
Pobrania
23
Wydruki
0
Wyświetlenia
266
Oceny
0

Aktualizacja u źródła:

Informacje o modelu

Źródło
Printables
Kategoria
Accessories
Licencja
Creative Commons — Public Domain

Overview

This is a DIY motorized turntable designed primarily for 3D scanning, but it can also be used as a product display turntable.

The project was designed in Fusion 360 and built as a weekend project for my personal needs. It works reliably for me, and I’m sharing it in case others find it useful or want to improve on it.


Electronics & Control

The turntable is powered by:

  • ESP32

  • 28BYJ-48 stepper motor

  • ULN2003 driver

  • Rotary encoder for:

    • Speed control

    • Direction control

    • Start/stop by pressing the encoder

Despite the small and inexpensive motor, the turntable is capable of rotating surprisingly heavy objects thanks to the large bearing-supported structure.

➡ Arduino (.ino) code and wiring diagram are included below.


Mechanical Design

  • Large plate diameter: 430 mm

  • The plate is split into 4 sections so it can be printed on smaller printers and then glued together.

  • Uses 608Z bearings (x5) for smooth rotation.

  • Detachable legs for easy storage and transport.

    • Legs can be fixed with M3 screws

    • Or even toothpicks for a quick, tool-free setup


Printing Notes

  • Plate sections need to be glued after printing

  • No special tolerances required

Parts Needed

  • 608Z bearings × 5

  • ESP32 × 1

  • 28BYJ-48 stepper motor × 1

  • ULN2003 driver × 1

  • Rotary encoder × 1

  • Jumper wires

  • M3 screws × 4 (or 12 for permanent leg mounting)

Future Improvements

This design works well for my use, but it’s not perfect. I may improve it in the future, and I invite anyone to modify, remix, or improve it as they see fit.

If you build it or change something—please share it!


Code and Readme:


#include <Arduino.h>

const uint8_t stepPins[4] = {21, 19, 18, 5};

const uint8_t encoderCLK = 15; const uint8_t encoderDT = 2; const uint8_t encoderSW = 4;

const uint8_t stepSequence[8][4] = { {1, 0, 0, 0}, {1, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 1}, {0, 0, 0, 1}, {1, 0, 0, 1} };

volatile int16_t encoderDelta = 0; int8_t currentStep = 0;

int16_t speedSetting = 0; int16_t currentSpeed = 0;

const int16_t speedIncrement = 2; // Encoder detent multiplier const int16_t maxSpeedSetting = 160; // Clamp for stability const uint32_t maxStepInterval = 4500; // Slowest (µs) const uint32_t minStepInterval = 900; // Fastest (µs) const uint8_t accelStep = 1; // Acceleration step

const uint32_t debounceMs = 50; bool paused = false; bool lastButtonState = HIGH; uint32_t lastButtonChange = 0;

uint32_t lastStepMicros = 0;

void IRAM_ATTR handleEncoder() { static uint8_t lastState = 0;

uint8_t state = (digitalRead(encoderCLK) << 1) | digitalRead(encoderDT); uint8_t transition = (lastState << 2) | state;

switch (transition) { case 0b0001: case 0b0111: case 0b1110: case 0b1000: encoderDelta++; break; case 0b0010: case 0b0100: case 0b1101: case 0b1011: encoderDelta--; break; default: break; }

lastState = state; }

void applyStep(int8_t stepIndex) { for (uint8_t i = 0; i < 4; i++) { digitalWrite(stepPins[i], stepSequence[stepIndex][i]); } }

void stepMotor(int direction) { currentStep = (currentStep + direction + 8) % 8; applyStep(currentStep); }

void setup() { for (uint8_t pin : stepPins) { pinMode(pin, OUTPUT); digitalWrite(pin, LOW); }

pinMode(encoderCLK, INPUT_PULLUP); pinMode(encoderDT, INPUT_PULLUP); pinMode(encoderSW, INPUT_PULLUP);

attachInterrupt(digitalPinToInterrupt(encoderCLK), handleEncoder, CHANGE); attachInterrupt(digitalPinToInterrupt(encoderDT), handleEncoder, CHANGE); }

void loop() { int16_t delta;

noInterrupts(); delta = encoderDelta; encoderDelta = 0; interrupts();

const bool buttonState = digitalRead(encoderSW); const uint32_t nowMs = millis();

if (buttonState != lastButtonState && (nowMs - lastButtonChange) > debounceMs) { lastButtonChange = nowMs; lastButtonState = buttonState;

if (buttonState == LOW) {
  paused = !paused;
  if (paused) {
    currentSpeed = 0;
  }
}

}

if (delta != 0) { speedSetting += delta * speedIncrement; speedSetting = constrain(speedSetting, -maxSpeedSetting, maxSpeedSetting); }

if (paused) { lastStepMicros = micros(); return; }

if (currentSpeed != speedSetting) { if (currentSpeed < speedSetting) currentSpeed += accelStep; else if (currentSpeed > speedSetting) currentSpeed -= accelStep; }

if (currentSpeed != 0) { const int8_t direction = (currentSpeed > 0) ? 1 : -1; const uint32_t speedLevel = abs(currentSpeed);

const uint32_t interval = constrain(
  map(speedLevel, 1, maxSpeedSetting, maxStepInterval, minStepInterval),
  minStepInterval,
  maxStepInterval
);

const uint32_t now = micros();

if (now - lastStepMicros &gt;= interval) {
  lastStepMicros = now;
  stepMotor(direction);
}

} }

ESP32 Turntable Controller

Simple ESP32 sketch that uses a rotary encoder to adjust the speed (and direction) of a 28BYJ-48 stepper motor through a ULN2003 driver board. Pressing the encoder button pauses/resumes motion.

Wiring

Power

  • ESP32 VIN (5 V from USB) → ULN2003 VCC
  • ESP32 GND → ULN2003 GND → Rotary encoder GND (common ground)
  • Rotary encoder + → ESP32 3.3 V

Stepper (via ULN2003 board)

ULN2003 pin ESP32 GPIO
IN1 21
IN2 19
IN3 18
IN4 5
Motor header 28BYJ-48

Rotary Encoder

Encoder pin ESP32 GPIO Notes
CLK 15 Interrupt input
DT 2 Interrupt input
SW 4 Button (pause/resume)
+ 3.3 V Use INTERNAL PULLUP
GND GND Share ground

Behavior

  • Turning the encoder clockwise increases speed in the forward direction.
  • Turning counter-clockwise decreases speed, eventually reversing direction.
  • Encoder button toggles pause/resume.

Notes

  • Keep the ULN2003 board powered from 5 V; the 28BYJ-48 needs more than 3.3 V.
  • Ensure the ESP32, ULN2003, and encoder share ground.
  • If you need higher top speed, consider a stronger stepper (e.g., NEMA 17 with DRV8825).

Tagi