Capturing the Milky Way, constellations, or a comet's trail without star‑trailing can be a nightmare---literally. A star‑tracker (also called an equatorial mount) rotates the camera at the same rate the Earth turns, keeping the stars stationary on the sensor while the landscape stays still. The result is smooth, long‑exposure night‑time timelapses that look like they were shot with professional gear.
Below is a step‑by‑step guide to designing and assembling a low‑cost, open‑source star‑tracker that you can build in a weekend with commonly available parts.
Core Concepts You Need to Know
| Concept | Why It Matters |
|---|---|
| Sidereal Rate | Stars appear to move ~15.041 arcseconds per second (≈ 360°/23 h 56 m 4 s). Your tracker must rotate at this speed to cancel the Earth's rotation. |
| Equatorial vs Alt‑Az | An equatorial (polar‑aligned) mount only needs a single rotational axis (right ascension). Alt‑az setups require a second axis and field‑derotation software. |
| Load Capacity | The motor and bearing must support the combined weight of your camera, lens, and any additionals (e.g., a small telescope). |
| Power Budget | Typical star‑trackers run on 5--12 V DC for hours. Choose a battery that can supply ≥1 A for the length of your shoot. |
Parts List
| Category | Recommended Item | Notes |
|---|---|---|
| Structure | 1 × 1‑inch stainless steel or aluminum square tube (≈ 1 m long) 1 × 1‑inch aluminum plate (base) | Rigid enough to resist flex but light enough to carry. |
| Bearing | 1 × 1‑inch stainless steel ball bearing (flanged) | Provides smooth rotation; choose a sealed unit to keep out dust. |
| Motor | 1 × 12 V DC planetary gear motor (≥ 50 : 1 reduction) or a stepper motor + gearbox (e.g., 200 steps/rev, 100 : 1) | Planetary geared DC motors are cheap and quiet; stepper gives fine micro‑stepping control. |
| Controller | Arduino Uno/Nano or ESP32 | Handles motor speed regulation and optional Bluetooth/Wi‑Fi UI. |
| Speed Sensor | 1 × Optical encoder (e.g., 500 PPR) or a Hall‑effect sensor with magnet | Enables closed‑loop control for precise sidereal speed. |
| Power | 12 V Li‑ion or Li‑poly battery (≥ 5 Ah) + DC‑DC buck‑converter (5 V) | Battery size depends on shoot length; a 5 Ah pack can run ~4 h at 1 A. |
| Mount Interface | 1/4‑20 tripod quick‑release plate (or a 1/4‑20 screw) | Standard camera mounting thread. |
| Misc. | Threaded rods, lock nuts, washers, nylon spacer, cable ties, heat‑shrink tubing, silicone grease, etc. | Keep a small electronics kit handy for wiring. |
Tip: Many of these items can be salvaged from old printers, scanners, or hobby drones, reducing cost to under $80.
Mechanical Assembly
3.1 Build the Polar Axis
- Cut the tube to the desired length (≈ 1 m works well for most DSLR/mirrorless cameras).
- Insert the bearing into one end of the tube. The flanged side should face outward; the open side faces the tube interior.
- Mount the motor on the bearing flange using a small plate and set‑screws. The motor shaft should line up collinearly with the bearing's axis.
- Attach the base plate to the opposite end of the tube with a threaded rod and a couple of lock nuts. This plate will sit on a tripod or a sturdy flat surface.
3.2 Add the Camera Platform
- Drill a 1/4‑20 hole in the center of a small aluminum plate (≈ 100 mm × 100 mm).
- Secure the plate to the motor shaft with a set‑screw or a small coupler.
- The plate now serves as a quick‑release platform ---just slide your camera's tripod mount onto it.
3.3 Polar Alignment Aids
- Attach a polar scope (a small low‑power sight tube) to the base. You can 3‑D print a simple polar scope holder that aligns with the bearing's rotational axis.
- Mark the north celestial pole (NCP) on the base using a small brass north‑star pointer or a laser level.
Electronics & Firmware
4.1 Wiring Overview
https://www.amazon.com/s?k=battery&tag=organizationtip101-20 (+12V) ----> https://www.amazon.com/s?k=motor&tag=organizationtip101-20 https://www.amazon.com/s?k=driver&tag=organizationtip101-20 (PWM) ----> https://www.amazon.com/s?k=motor&tag=organizationtip101-20
https://www.amazon.com/s?k=battery&tag=organizationtip101-20 (+12V) ----> https://www.amazon.com/s?k=Arduino&tag=organizationtip101-20 VIN (or 5V https://www.amazon.com/s?k=regulator&tag=organizationtip101-20)
https://www.amazon.com/s?k=Arduino&tag=organizationtip101-20 GND ------- https://www.amazon.com/s?k=motor&tag=organizationtip101-20 https://www.amazon.com/s?k=driver&tag=organizationtip101-20 GND
Encoder A/B ------- https://www.amazon.com/s?k=Arduino&tag=organizationtip101-20 digital https://www.amazon.com/s?k=pins&tag=organizationtip101-20 (interrupt)
PWM https://www.amazon.com/s?k=pin&tag=organizationtip101-20 ----------> https://www.amazon.com/s?k=Arduino&tag=organizationtip101-20 PWM output (e.g., D9)
4.2 Motor Driver Options
| Driver | Why Choose It |
|---|---|
| TB6612FNG (dual H‑bridge) | Handles up to 1.2 A continuous, inexpensive, simple PWM control. |
| DRV8835 | Similar to TB6612, but with a slightly higher current rating (1.5 A). |
| A4988 + Stepper | If you use a stepper motor, the A4988 provides micro‑stepping and current limiting. |
4.3 Sample Arduino Sketch (DC Motor + Encoder)
// Star‑https://www.amazon.com/s?k=tracker&tag=organizationtip101-20 https://www.amazon.com/s?k=controller&tag=organizationtip101-20 -- https://www.amazon.com/s?k=Arduino&tag=organizationtip101-20 https://www.amazon.com/s?k=Uno&tag=organizationtip101-20/Nano
// ------------------------------------------------
// https://www.amazon.com/s?k=hardware&tag=organizationtip101-20: 12 V https://www.amazon.com/s?k=DC&tag=organizationtip101-20 https://www.amazon.com/s?k=motor&tag=organizationtip101-20 + TB6612 https://www.amazon.com/s?k=driver&tag=organizationtip101-20 + 500 PPR optical encoder
// ------------------------------------------------
const int PWM_PIN = 9; // https://www.amazon.com/s?k=motor&tag=organizationtip101-20 speed (0‑255)
const int DIR_PIN = 8; // https://www.amazon.com/s?k=motor&tag=organizationtip101-20 direction
const int ENC_A = 2; // Encoder channel A (interrupt)
const int ENC_B = 3; // Encoder channel B (interrupt)
// Sidereal speed = 0.004178 rad/s ≈ 0.24°/s
// For a 1‑inch (25.4 mm) bearing radius:
const https://www.amazon.com/s?k=Float&tag=organizationtip101-20 WHEEL_DIAM_MM = 25.4;
const https://www.amazon.com/s?k=Float&tag=organizationtip101-20 CIRCUMFERENCE_MM = PI * WHEEL_DIAM_MM;
const https://www.amazon.com/s?k=Float&tag=organizationtip101-20 SIDEREAL_MM_PER_SEC = (CIRCUMFERENCE_MM / (23.9344696 * 3600.0)); // ≈0.087 mm/s
volatile long encoderTicks = 0;
unsigned long lastPrint = 0;
void setup() {
pinMode(PWM_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(ENC_A, INPUT_PULLUP);
pinMode(ENC_B, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENC_A), onEncoderA, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENC_B), onEncoderB, CHANGE);
// Initialise https://www.amazon.com/s?k=motor&tag=organizationtip101-20 stopped
analogWrite(PWM_PIN, 0);
digitalWrite(DIR_PIN, HIGH);
Serial.begin(115200);
}
void loop() {
// Compute https://www.amazon.com/s?k=Current&tag=organizationtip101-20 speed in https://www.amazon.com/s?k=ticks&tag=organizationtip101-20 per second
static long lastTicks = 0;
static unsigned long lastTime = millis();
unsigned long now = millis();
long dt = now - lastTime;
if (dt >= 200) { // update every 200 ms
long diff = encoderTicks - lastTicks;
https://www.amazon.com/s?k=Float&tag=organizationtip101-20 ticksPerSec = diff * 1000.0 / dt;
// Convert https://www.amazon.com/s?k=ticks&tag=organizationtip101-20 to linear speed (mm/s)
// Encoder gives 500 pulses per https://www.amazon.com/s?k=motor&tag=organizationtip101-20 rev; https://www.amazon.com/s?k=gear&tag=organizationtip101-20 ratio ~ 50:1
const https://www.amazon.com/s?k=Float&tag=organizationtip101-20 GEAR_RATIO = 50.0;
const https://www.amazon.com/s?k=Float&tag=organizationtip101-20 PULSES_PER_REV = 500.0;
https://www.amazon.com/s?k=Float&tag=organizationtip101-20 revsPerSec = ticksPerSec / (PULSES_PER_REV * GEAR_RATIO);
https://www.amazon.com/s?k=Float&tag=organizationtip101-20 mmPerSec = revsPerSec * CIRCUMFERENCE_MM;
// Simple PI https://www.amazon.com/s?k=controller&tag=organizationtip101-20 to reach sidereal speed
static https://www.amazon.com/s?k=Float&tag=organizationtip101-20 integral = 0;
const https://www.amazon.com/s?k=Float&tag=organizationtip101-20 Kp = 30.0;
const https://www.amazon.com/s?k=Float&tag=organizationtip101-20 Ki = 5.0;
https://www.amazon.com/s?k=Float&tag=organizationtip101-20 error = SIDEREAL_MM_PER_SEC - mmPerSec;
integral += error * (dt / 1000.0);
https://www.amazon.com/s?k=Float&tag=organizationtip101-20 output = Kp * error + Ki * integral; // PWM value (0‑255)
// https://www.amazon.com/s?k=clamp&tag=organizationtip101-20 and write
int pwm = constrain(int(output), 0, 255);
analogWrite(PWM_PIN, pwm);
// Debug print every second
if (now - lastPrint >= 1000) {
Serial.print("Speed (mm/s): "); Serial.print(mmPerSec, 4);
Serial.print(" | PWM: "); Serial.println(pwm);
lastPrint = now;
}
lastTicks = encoderTicks;
lastTime = now;
}
}
// ----------------------------------------------------------------
// Encoder ISR -- quadrature decoding
// ----------------------------------------------------------------
void onEncoderA() {
bool a = digitalRead(ENC_A);
bool b = digitalRead(ENC_B);
encoderTicks += (a == b) ? +1 : -1;
}
void onEncoderB() {
bool a = digitalRead(ENC_A);
bool b = digitalRead(ENC_B);
encoderTicks += (a != b) ? +1 : -1;
}
Explanation of the sketch
- Encoder feedback gives us the actual rotation speed.
- A tiny PI controller adjusts PWM until the linear speed at the bearing edge matches the sidereal rate.
- The code assumes a 50 : 1 gear reduction; modify
GEAR_RATIOto match your motor. - You can replace the PI loop with a simple fixed PWM if you calibrate manually (e.g., set PWM ≈ 90 for a 12 V motor).
4.4 Optional Bluetooth UI (ESP32)
If you'd rather tweak speed on the fly, replace the UNO with an ESP32 and pair it with a smartphone app (e.g., Serial Bluetooth Terminal). Expose a single command S<value> where <value> is the PWM target (0‑255).
Polar Alignment Procedure
- Set the base on a stable tripod and level it using a bubble level.
- Point the bearing's axis roughly toward true north.
- Mount the polar scope (or simply use a smartphone compass + an inclinometer app).
- Align the sight :
- Locate Polaris (the North Star) and center it in the polar scope's reticle.
- Adjust the azimuth and elevation of the base until Polaris sits precisely at the reticle's "North Celestial Pole" mark.
- Fine‑tune : Run the tracker for a couple of minutes and watch a test exposure (e.g., 30 s). If stars show a slight drift, nudge the axis a few arc‑minutes and test again.
Remember : Alignment error of 1° yields a tracking error of ~1 % (≈ 0.9 seconds of arc per minute). For typical timelapse intervals (5‑30 s), a 5--10 arc‑minute alignment is more than sufficient.
Shooting Tips & Workflow
| Step | Recommendation |
|---|---|
| Battery Planning | Charge a fresh 12 V pack the night before. A 5 Ah battery can supply 1 A for ~5 h; factor in loss from the driver (≈ 10 %). |
| Camera Settings | Use ISO 800--3200, aperture f/2.8‑f/4, exposure 20--30 s. If you want "star‑trails" instead, disable the tracker. |
| Intervalometer | Set interval ≈ 3 × exposure time to allow memory‑card write (e.g., 30 s exposure → 100 s interval). |
| Focus | Switch to manual focus; use Live View + focus magnification on a bright star. |
| Weather Protection | Enclose the electronics in a waterproof box with a small vent (use a breathable membrane). |
| Remote Monitoring | Connect a small OLED or LED strip to the Arduino to show live PWM; or use the ESP32 Bluetooth UI for real‑time changes. |
Common Pitfalls & How to Fix Them
| Problem | Diagnosis | Fix |
|---|---|---|
| Stars drift despite alignment | Encoder reports ~0 ppm error; motor_PWM near max. | Check gear backlash; add a tensioner or use a toothed belt reduction instead of a simple gear train. |
| Motor stalls at low temperatures | Battery voltage sagging < 11 V. | Use a Li‑FePO₄ pack (stable voltage) or a small solar panel to keep voltage up. |
| Vibration blurs the foreground | Bearing not greased or loose mounting screws. | Apply a dab of silicone grease to the bearing race and torque all fasteners to spec (≈ 8 Nm). |
| Battery runs out early | Running the motor at full PWM for long shoots. | Lower PWM to the minimum that still meets sidereal speed; run a longer interval to reduce duty cycle. |
| Encoder misreads (jittery speed) | Electrical noise from motor leads. | Twist the encoder wires with the motor leads (forming a twisted pair) and add a 0.1 µF decoupling capacitor across encoder VCC/GND. |
Upgrades for the Future
- Field‑derotation : Add a second motor on a rotating platform to compensate for the rotating sky when you need an alt‑az mount.
- GPS & Time Sync : Use an ESP32 with a GPS module to automatically set the local sidereal time, letting the tracker auto‑align at startup.
- 3‑D‑Printed Housing : Design a modular enclosure that bolts directly onto standard 1‑inch tripods, making the whole rig portable.
- App Integration : Build a mobile app that reads the encoder via Bluetooth and offers a graphical "speed dial" plus a polar‑alignment AR overlay.
Final Thoughts
A DIY star‑tracker transforms an ordinary camera into a night‑sky storyteller. By combining a low‑cost DC motor, a precise bearing, and a closed‑loop controller, you get sidereal‑rate tracking accuracy comparable to entry‑level commercial mounts. The biggest reward isn't just the stunning timelapse footage---it's the satisfaction of building a device that moves exactly with the celestial sphere.
Now that you have the blueprint, gather your tools, charge that battery, and start turning the heavens into a smooth, flowing canvas. Happy shooting! 🌌🚀