I wanted to use this week to understand which motors would be best for my final project, Glowmorph. The kinetic lamp is essentially a puppet, where all the motors are hidden in the base plate, and cables are routed through to actuate its arms. This is done to save space in the lamp and keep it lightweight, with no bulky inner node.
This week I aimed to get one of these arms working. Not an unreasonable goal, but we’ll see.
My proposed construction sequence for a single kinetic arm. Much still to refine, but the overall logic is there.
I built a test arm upside down so gravity could assist retraction:
For this circuit, I used a Texas Instruments DRV8251A.
Being new to motor drivers, I started by replicating Neil’s schematic and PCB, then adapting his code from the class site.
Before testing the motor, I verified the Time‑of‑Flight sensor and limit switch. The terminal displayed distance readings and switch states as expected.
#include#include #include #define STEPS_PER_REV 48 #define IN1 A0 #define IN2 A1 #define IN3 A2 #define IN4 A3 #define LIMIT_PIN D8 Stepper stepper(STEPS_PER_REV, IN1, IN3, IN2, IN4); Adafruit_VL53L1X vl53 = Adafruit_VL53L1X(); int dir = 1; void setup() { Serial.begin(115200); Wire.begin(); pinMode(LIMIT_PIN, INPUT_PULLUP); Serial.println("Initializing Stepper + VL53L1X..."); if (!vl53.begin(0x29, &Wire)) { Serial.print(F("Error initializing VL53L1X sensor. Status: ")); Serial.println(vl53.vl_status); while (1) delay(10); } vl53.startRanging(); vl53.setTimingBudget(50); stepper.setSpeed(10); Serial.println("Setup complete."); } void loop() { int16_t distance = vl53.distance(); if (distance > 0) { int speed = map(distance, 50, 400, 10, 80); speed = constrain(speed, 5, 100); stepper.setSpeed(speed); } if (digitalRead(LIMIT_PIN) == LOW) { dir *= -1; delay(300); } stepper.step(dir); }
The motor didn’t turn — just a faint hum and a whiff of “motor smell.” This led to a long debugging session. After fabricating my own dual H‑bridge board based on Neil’s DRV8251A design, the first tests failed completely. Below is a record of what I discovered.
Testing electrical signals using the oscilloscope.
Bench supply confirmed stable voltage across VM and GND.
Signals reached the upper H‑bridge inputs but not the lower one — a key clue.
I copied Neil’s schematic and code, connecting two DRV8251ADDAR half‑bridges to my RP2040. The top driver (U2) showed signals; the bottom (U3) was silent.
I confirmed IN1 → SCL (D5) and IN2 → TX (D6) matched Neil’s defines. Still, VB (PWM input) had no signal.
A continuity test showed VB never actually reached Xiao D4. I patched the trace with a jumper, and PWM appeared at both VA and VB.
U3’s power pin was floating low — the driver stayed asleep. I added 10 kΩ pull‑ups to 3.3 V for both nSLEEP pins. With VM ≈ 9 V and logic = 3.3 V, I still got only faint motion.
The major oversight: I connected VM to the board’s 5 V rail. Neil’s original board isolates VM with a 0 Ω link; keeping it tied to USB 5 V caused feedback spikes and likely fried the Xiao. After removing the 0 Ω link and powering VM separately (9–12 V), things stabilized.
Reflowing both DRV8251As — especially VREF, IN1/IN2, and nSLEEP — restored functionality. IPROPI outputs each route through 499 Ω to GND for current sensing. A new RP2040 confirmed PWM stability on both channels.
Some lessons are learned the hard way — connecting VM and USB 5 V taught me that quickly.