Banner publicitario de PCBWay

Comunicación entre escáner ( iluminación) conector BM9 ( 9 pines )

estuve mirando videso y no encontre motores paso a paso que se muevan rapido, creo que un paso a paso no tiene la reaccion para hacer los barridos de una punta a la otra a buena velocidad como muestra el video de funcionamiento original . talvez los topes no sean topes en si , si no centradores y amortiguadores, o sea que talvez sea normal que golpee el motor para que entre en juego el embriage del resorte
Como que no? Si señor, se puede tener muy buena velocidad 😉
Mira estos videos; no refiere al tema principal, pero mira la velocidad del PAP


 
estuve mirando videso y no encontre motores paso a paso que se muevan rapido, creo que un paso a paso no tiene la reaccion para hacer los barridos de una punta a la otra a buena velocidad como muestra el video de funcionamiento original . talvez los topes no sean topes en si , si no centradores y amortiguadores, o sea que talvez sea normal que golpee el motor para que entre en juego el embriage del resorte
Creo que tienes una idea equivocada de los PAP. 🤦‍♀️

Por ejemplo los 42PM48L-01 de 7.5° son usados en los Scanner económicos, incluso los M42SP-5 de 7.5° que los encuentras a montones en impresoras son perfectos para este tipo de proyectos.

Los que usa los Revo Scan son muy rápidos y son como los que indico 42PM48L-01 de 7.5°, como que no encuentras mas bien eso si cuestan mas de lo normal.


1765051811263.png

Los PAP dependen del Step Angle entre mismo sea menor este alcanzara velocidades mas altas, los hay desde un ángulo de paso de 0.9°, 1,8°, 3.6° y así sucesivamente, por ejemplo uno de 1.8° necesita 200 pasos para dar una vuelta, uno de 7.5° 48 pasos por vuelta, ves la diferencia.

Revo Scann.jpg

La velocidad depende de la frecuencia de los pulsos de control y del numero de dientes del rotor😁, si estos se configuran en Microstep son mas precisos pero pierden fuerza en cambio en paso completo o Fullstep tiene mas torque pero por ende hay mas vibración.


Un par de diagramas y demás de un Scanner y así se nos damos una buena idea de como es su funcionamiento el cual integra el famoso CMOS CD4093.

Scaner Motor Driver Kitana.jpg


Scaner MotoSwitches Kitana.jpg






Un ejemplo de una restauración y así se puede apreciar todo incluso casi se puede palpar.



Viejo dicho >Colombiano si quieren mas que le piquen caña :ROFLMAO:🤦‍♀️
 

Adjuntos

  • Kitana Explosion Drawing StageScan.pdf
    677.1 KB · Visitas: 1
  • Kitana Schematics StageScan.pdf
    445.5 KB · Visitas: 1
  • M42SP-5.PDF
    59 KB · Visitas: 0
  • 42PM48L01.pdf
    133.1 KB · Visitas: 0
Última edición:
Hola a todos
Bueno creo que habria que definir que quiere hacer
Yo estoy dispuesto a colaborar . dentro del poco tiempo que tengo disponible .
Ya sea en clonar la placa con el sprint layout ., o si quiere hacerlo con micro y motores pap
Pero como dice el maestro Kitana y el querido profe torres.electronico ., eso seria mas caro y mas complejo
Esos motores con reductora., se usan mucho en los espiedo de los hornos de las cosinas domesticas
Con respecto a usar micros., NO SERIA CON ARDUINO .,.si bien usariamos AVR como el ATTINy328p ., es con otro lenguaje de programcion
Yo creo que ya esta demostrado que info y soluciones hay de sobra ja ja ja ja ja ja
Subo 2 videos en .RAR que No estan en youtube sobre moviento de pap usando dmx
En los dos trato de explicar (muy mal por cierto) la aceleracion y torque de los pap
Bajen los .RAR dele a desconprimir el primero de cada uno y solo se juntan los videos
ATTE : juan
 

Adjuntos

  • Prueba 2 dmx steeper.part2.rar
    10 MB · Visitas: 0
  • Prueba 2 dmx steeper.part1.rar
    10 MB · Visitas: 0
  • Prueba 1 dmx steeper.part3.rar
    1.3 MB · Visitas: 0
  • Prueba 1 dmx steeper.part2.rar
    10 MB · Visitas: 0
  • Prueba 1 dmx steeper.part1.rar
    10 MB · Visitas: 0
  • Prueba 2 dmx steeper.part3.rar
    10 MB · Visitas: 0
  • Prueba 2 dmx steeper.part4.rar
    1.3 MB · Visitas: 0
Como que no? Si señor, se puede tener muy buena velocidad 😉
Mira estos videos; no refiere al tema principal, pero mira la velocidad del PAP


Si se ven mucho más rápidos de los que ví. Porsupuesto todo tiene que ver con la relación de sus reductores. Pero no miento he visto videos con papá probados a su máxima velocidad y lo primero que pensé que lo máximo que podría aspirar era cambiar a colores de al lado . De todas formas el DC no es una opción precisa y el servo no gira 360° así que no hay elección. Llevará un paso a paso.
 
Tirada de cables:
aclarando que todavía tengo que conseguir herramientas para desmantelar la plaqueta sin romper ( el chupador de antaño) . La scaneee, Ustedes se encarguen de clonar y simular. Luego de la devolución las mande a imprimir, compre todos los componentes , los suelde y quedé bien . Hay un largo camino .
Por lo que mientras tanto continuaremos simulando la placa con Arduino.
El problema que se presenta ahora es como el título lo dice : tirada de cables.
Lo que tengo pensado es hacerme una cajita fuera de borda , nada del otro mundo , una cajita de madera con una tapa ,que pienso tener en mi mesa al lado de la PC por ejemplo por si necesito conectar para modificar algo ..o en el rack.
Dicha caja mágica que contendra la fuente , el arduino, los 2 puente h y los drivers de los paso a paso.
Por detras tendra conector interlook o algo similar para alimentar la fuente.
Y la salida hacia los escáners.

Los voy a dividir en dos grupos de 2 .
Es decir un puente h para 4 dc. Puentiando alimentación directo de la salida a los motores del módulo.
Entonces para los motores DC. Pienso llevar la señal lista , es decir 4 cables , dos para motor abajo- arriba y 2 para motor iz- derecha. Los cuales se copiaran al otro scaner.
Y con el otro grupo de scaner lo mismo descrito arriba

Entonces pensé utilizar utp . Es decir un solo conductor de 8 conductores que atraviese los 4 scaner.
4 pines quedan en los primeros dos .
Y los otros 4 pines alimentan el otro grupo.
Hasta ahí estamos
Ahora lo que necesito saber es si puedo puentiar dos motores paso a paso en unos solo driver?🤔🤔🤔 Para hacer lo mismo
Dependiendo la respuesta sería la cantidad y tipo de conductor que necesito.
Hame olvidaba de aclarar que entre aparato y aparato le vamos a dejar máximo 1.5 m . Por lo que la tirada más larga hasta el último scaner entre bajada y todo serían unos 10m

Lampara halógena o led ?
se me ocurrió analizar la idea de dejar de depender de los Transformers pesados (y usarlos en algún proyecto de audio ) y talvez cuando tenga la placa puedo alimentarla directamente con la fuente . Es de 12v 10A.
Por lo que para las luces tengo las siguientes opciones ( más económicas)
1- lámparas de cuarzo 220v 500w ,se que se desperdicia energía porque no se concentra. Pero talvez podría con aislar parte de la luz más la dos lupas que tengo en el scaner alcanzaría bien.

2- chip cob led blanco 100w 220. Algo que tampoco concentra al 100% la luz ( ya que no dispongo de 4 colimadored) además de requerir difusor de calor y talvez ventilacion adicional. Tampoco estoy seguro de la potencia lumínica final.
3- viendo los vídeos rusos note que utilizan leds RGB . Entonces otra opción sería ponerle varios led de alta potencia ( 3w cada color ) . Supongo que necesitaría de otra fuente de 24v y para controlar los colores vi unos que vienen para luces de pileta con control remoto y presets ya programados. El problema de estos es el consumo de los leds. Estamos hablando de casi 3 amperes por led por lo que necesitaria una fuente enorme y no creo que el controlador RGB soporte toda la potencia
 

Adjuntos

  • Screenshot_20251207_090208.jpg
    Screenshot_20251207_090208.jpg
    109.5 KB · Visitas: 2
  • Screenshot_20251207_090243.jpg
    Screenshot_20251207_090243.jpg
    149.7 KB · Visitas: 0
  • Screenshot_20251207_090449.jpg
    Screenshot_20251207_090449.jpg
    171.1 KB · Visitas: 0
  • Screenshot_20251207_090322.jpg
    Screenshot_20251207_090322.jpg
    145.4 KB · Visitas: 2
  • Screenshot_20251207_090342.jpg
    Screenshot_20251207_090342.jpg
    186.6 KB · Visitas: 2
  • IMG_20251207_092332.jpg
    IMG_20251207_092332.jpg
    188.5 KB · Visitas: 1
  • IMG_20251207_092341.jpg
    IMG_20251207_092341.jpg
    163.3 KB · Visitas: 1
Última edición:
Yo estoy dispuesto a colaborar . dentro del poco tiempo que tengo disponible .
Ya sea en clonar la placa con el sprint layout ., o si quiere hacerlo con micro y motores pap
Muchas gracias por esa maravillosa colaboración y sacar de tu tiempo disponible para brindar una mano se te agradece inmensamente tus grandes aportes, de igual manera de mi parte tratare de sacar un tiempo y a lo mejor podamos clonarla conjuntamente te parece.

":ROFLMAO:A ver si nos volvemos Masters en clonación de animales Extintos y nos tomamos unos tintos :ROFLMAO: " { Tinto es un café cargado Colombiano }

Pero como dice el maestro Kitana
1765131514073.png

Maestro🙋‍♀️ 🤣, bueno si me gustaría ser una docente pero aun me falta mucho por recorrer.
 
Última edición:
Bueno, arme 7 versiones distintas con el driver uln2003 y el motor 28BYJ-48 y no me termino de convencer...

CSS:
/*/////////////////////////////////////////////////////////////////////////////////
//  ArduRITMICO v4.0g - Scanner DJ – FFT +28BYJ-48 +ULN2003 + KY037 (v1.0)
// ETI Patagonia - prof.martintorres@educ.ar - https://github.com/ETI-PATAGONIA-AR
///////////////////////////////////////////////////////////////////////////////////
   - Arduino Nano
   - ULN 2003
   - 28BYJ-48
   - KY-037 analog -> A0
   - Pots: A1 (B/M) , A2 (M/A), A3 (gain RGB), A4 (maxTiltSteps), A5 (maxPanSteps)
   - Vert: 2,3,4,5  Horiz: 6,7,8,12
   - RGB MOSFET gates: D9 (R), D10 (G), D11 (B)  (N-channel MOSFET low-side)
   - Button mode / save: D13 (INPUT_PULLUP, press to GND)
   - librerias: fix_fft, AccelStepper, EEPROM
*/

#include <fix_fft.h>
#include <AccelStepper.h>
#include <EEPROM.h>
#include <math.h>

// ---------------- CONFIG PINES ----------------
#define AUDIO_PIN A0
#define POT_BM A1
#define POT_MA A2
#define POT_GAIN A3
#define POT_TILT_MAX A4
#define POT_PAN_MAX A5

AccelStepper stepperVert(AccelStepper::FULL4WIRE, 2, 3, 4, 5);
AccelStepper stepperHoriz(AccelStepper::FULL4WIRE, 6, 7, 8, 12);

#define PIN_R 9
#define PIN_G 10
#define PIN_B 11

#define BUTTON_PIN 13  // INPUT_PULLUP -> press to GND

// ---------------- FFT / BUFFERS ----------------
#define MUESTRAS 128
#define LOGM 7
#define BIN_OFFSET 2   // ignorar DC / ruido

char vReal[MUESTRAS];
char vImag[MUESTRAS];
unsigned long magn[MUESTRAS/2];

// ---------------- MOTION / STEPS ----------------
// 28BYJ-48 typical half-step ~4096 steps/rev depending firmware; usamos 4096
const long STEPS_PER_REV = 4096L;
const int DEFAULT_PAN_STEPS = STEPS_PER_REV / 2;   // 180° -> 2048
const int DEFAULT_TILT_STEPS = STEPS_PER_REV / 4;  //  90° -> 1024

int maxStepsPan = DEFAULT_PAN_STEPS;
int maxStepsTilt = DEFAULT_TILT_STEPS;

long centerPan = 0;
long centerTilt = 0;

float phasePan = 0;
float phaseTilt = 0;
float basePhaseInc = 0.015; // base increment for smooth motion

// kick parameters
int kickStepsPanBase = 120;
int kickStepsTiltBase = 140;
int kickDecayMs = 120;
long kickTargetPan = 0;
unsigned long kickEndPan = 0;
long kickTargetTilt = 0;
unsigned long kickEndTilt = 0;

// ---------------- RGB / LIGHTS ----------------
float gainRGB = 1.0;
const unsigned long MAX_MAGN_EXPECTED = 12000UL; // ajustar si hace falta

// ---------------- LIMIT BINS (pots) ----------------
int binBMax = 7;
int binMMax = 35;

// ---------------- STROBE / MODES ----------------
bool strobeEnabled = true;
int strobeThreshold = 2500;
unsigned long lastStrobe = 0;
int strobeLenMs = 40;

enum MODE {MODE_SIN=0, MODE_BEAT=1, MODE_STROBE=2, MODE_RANDOM=3, MODE_IDLE=4};
MODE currentMode = MODE_SIN;

// ---------------- EEPROM ADDRESSES ----------------
const int EE_ADDR_VALID = 0;
const int EE_ADDR_MODE = 1;
const int EE_ADDR_PAN = 10;   // 2 bytes
const int EE_ADDR_TILT = 20;  // 2 bytes
const int EE_ADDR_GAIN = 30;  //byte (0..255)

// ---------------- SMOOTHERS ----------------
float smoothB = 0, smoothM = 0, smoothA = 0;

// ---------------- UTILS ----------------
unsigned long lastMillis = 0;
unsigned long sampleDelayMs = 8;

void setup() {
  pinMode(PIN_R, OUTPUT);
  pinMode(PIN_G, OUTPUT);
  pinMode(PIN_B, OUTPUT);

  digitalWrite(PIN_R, LOW);
  digitalWrite(PIN_G, LOW);
  digitalWrite(PIN_B, LOW);

  pinMode(BUTTON_PIN, INPUT);

  stepperVert.setMaxSpeed(1200);
  stepperVert.setAcceleration(2000);
  stepperHoriz.setMaxSpeed(1200);
  stepperHoriz.setAcceleration(2000);
  stepperVert.setCurrentPosition(0);
  stepperHoriz.setCurrentPosition(0);

  centerPan = 0;
  centerTilt = 0;

  // ADC ref
  analogReference(INTERNAL); // más sensible para mic con voltajes bajos (si KY-037 funciona ok)
  delay(50);

  loadConfigFromEEPROM();
}

void loop() {
  unsigned long now = millis();

  int pBM = analogRead(POT_BM);
  int pMA = analogRead(POT_MA);
  int pGain = analogRead(POT_GAIN);
  int pTiltMax = analogRead(POT_TILT_MAX);
  int pPanMax = analogRead(POT_PAN_MAX);

  int minBin = BIN_OFFSET + 0;
  binBMax = constrain(map(pBM, 0, 1023, minBin+1, 14), minBin+1, 24);
  binMMax = constrain(map(pMA, 0, 1023, binBMax+1, MUESTRAS/2 - 1), binBMax+1, MUESTRAS/2 - 1);

  gainRGB = constrain(map(pGain, 0, 1023, 50, 350) / 100.0, 0.5, 3.5);
  maxStepsTilt = constrain(map(pTiltMax, 0, 1023, 64, DEFAULT_TILT_STEPS), 32, DEFAULT_TILT_STEPS);
  maxStepsPan  = constrain(map(pPanMax, 0, 1023, 64, DEFAULT_PAN_STEPS), 64, DEFAULT_PAN_STEPS);

  for (int i = 0; i < MUESTRAS; i++) {
    int raw = analogRead(AUDIO_PIN);
    int v = raw / 4 - 128;
    if (v < -128) v = -128;
    if (v > 127) v = 127;
    vReal[i] = (char)v;
    vImag[i] = 0;
  }


  aplicaVentana(vReal);
  fix_fft(vReal, vImag, LOGM, 0);

  // magnitudes
  for (int b = 0; b < MUESTRAS/2; b++) {
    int re = (int)vReal[b];
    int im = (int)vImag[b];
    unsigned long mag = (unsigned long)(re * re) + (unsigned long)(im * im);
    magn[b] = mag;
  }

  unsigned long sumB = 0;
  for (int b = BIN_OFFSET; b <= binBMax; b++) sumB += magn[b];

  unsigned long sumM = 0;
  for (int b = binBMax + 1; b <= binMMax; b++) sumM += magn[b];

  unsigned long sumA = 0;
  for (int b = binMMax + 1; b < MUESTRAS/2; b++) sumA += magn[b];

  // smoothing
  smoothB = smoothB * 0.75 + sumB * 0.25;
  smoothM = smoothM * 0.75 + sumM * 0.25;
  smoothA = smoothA * 0.75 + sumA * 0.25;

  float normB = constrain((sumB / (float)MAX_MAGN_EXPECTED) * gainRGB, 0.0, 1.0);
  float normM = constrain((sumM / (float)MAX_MAGN_EXPECTED) * gainRGB, 0.0, 1.0);
  float normA = constrain((sumA / (float)MAX_MAGN_EXPECTED) * gainRGB, 0.0, 1.0);

  float totalEnergy = constrain((sumB + sumM + sumA) / (3.0 * (float)MAX_MAGN_EXPECTED) * gainRGB, 0.0, 1.0);

  bool beatB = (sumB > smoothB * 1.6);
  bool beatA = (sumA > smoothA * 1.6);

  if (beatB) {
    int dir = (random(0,2) ? 1 : -1);
    kickTargetTilt = centerTilt + dir * (kickStepsTiltBase + (int)(normB * kickStepsTiltBase));
    kickEndTilt = now + kickDecayMs;
  }
  if (beatA) {
    int dir = (random(0,2) ? 1 : -1);
    kickTargetPan = centerPan + dir * (kickStepsPanBase + (int)(normA * kickStepsPanBase));
    kickEndPan = now + kickDecayMs;
  }

  bool strobeNow = false;
  if (strobeEnabled && sumA > strobeThreshold && currentMode == MODE_STROBE) {
    strobeNow = true;
    lastStrobe = now;
  }

  if (strobeNow) {
    flashRGB(255,255,255);
  } else {
    renderRGB(normB, normM, normA, totalEnergy, beatB, beatA);
  }

  float panSpeedFactor = 0.5 + totalEnergy * 3.0;
  float tiltSpeedFactor = 0.5 + totalEnergy * 3.5;
  phasePan += basePhaseInc * panSpeedFactor;
  phaseTilt += basePhaseInc * tiltSpeedFactor;

  long targetPan = centerPan + (long)( sin(phasePan) * maxStepsPan * totalEnergy );
  long targetTilt = centerTilt + (long)( sin(phaseTilt) * maxStepsTilt * totalEnergy );

  if (now < kickEndPan) {
    float frac = float(kickEndPan - now) / float(kickDecayMs);
    frac = constrain(frac, 0.0, 1.0);
    targetPan = (long)( targetPan * (1.0 - frac) + kickTargetPan * frac );
  } else {
    kickTargetPan = centerPan;
  }
  if (now < kickEndTilt) {
    float frac = float(kickEndTilt - now) / float(kickDecayMs);
    frac = constrain(frac, 0.0, 1.0);
    targetTilt = (long)( targetTilt * (1.0 - frac) + kickTargetTilt * frac );
  } else {
    kickTargetTilt = centerTilt;
  }

  if (targetPan > centerPan + maxStepsPan) targetPan = centerPan + maxStepsPan;
  if (targetPan < centerPan - maxStepsPan) targetPan = centerPan - maxStepsPan;
  if (targetTilt > centerTilt + maxStepsTilt) targetTilt = centerTilt + maxStepsTilt;
  if (targetTilt < centerTilt - maxStepsTilt) targetTilt = centerTilt - maxStepsTilt;

  switch (currentMode) {
    case MODE_SIN:

      break;
    case MODE_BEAT:

      if (!beatA && !beatB) {
        targetPan = (long)(targetPan * 0.8 + centerPan * 0.2);
        targetTilt = (long)(targetTilt * 0.8 + centerTilt * 0.2);
      }
      break;
    case MODE_RANDOM:
      targetPan += random(-20, 21);
      targetTilt += random(-15, 16);
      break;
    case MODE_IDLE:
      targetPan = (long)(centerPan + sin(phasePan) * (maxStepsPan * 0.15));
      targetTilt = (long)(centerTilt + sin(phaseTilt) * (maxStepsTilt * 0.12));
      break;
    case MODE_STROBE:
      break;
  }

  stepperHoriz.moveTo(targetPan);
  stepperVert.moveTo(targetTilt);

  stepperHoriz.run();
  stepperVert.run();

  handleButton();

  delay(sampleDelayMs);
}

void aplicaVentana(char *vData) {
  double n1 = double(MUESTRAS) - 1.0;
  for (int i = 0; i < MUESTRAS/2; i++){
    double r = double(i) / n1;
    double w = 0.5 * (1.0 - cos(6.283185307179586 * r));
    vData[i] = (char)((double)vData[i] * w);
    vData[MUESTRAS - 1 - i] = (char)((double)vData[MUESTRAS - 1 - i] * w);
  }
}

void renderRGB(float nB, float nM, float nA, float energy, bool beatB, bool beatA) {
  // build components
  float rf = nA; // agudos -> rojo
  float gf = nM; // medios -> verde
  float bf = nB; // bajos -> azul

  rf = constrain(rf * 0.9 + energy * 0.4, 0.0, 1.0);
  gf = constrain(gf * 0.9 + energy * 0.4, 0.0, 1.0);
  bf = constrain(bf * 0.9 + energy * 0.4, 0.0, 1.0);

  if (beatB) bf = min(1.0, bf + 0.45);
  if (beatA) rf = min(1.0, rf + 0.45);

  uint8_t R = (uint8_t)(rf * 255.0);
  uint8_t G = (uint8_t)(gf * 255.0);
  uint8_t B = (uint8_t)(bf * 255.0);

  analogWrite(PIN_R, R);
  analogWrite(PIN_G, G);
  analogWrite(PIN_B, B);
}

void flashRGB(uint8_t R, uint8_t G, uint8_t B) {
  analogWrite(PIN_R, R);
  analogWrite(PIN_G, G);
  analogWrite(PIN_B, B);
}

// ---------------- BUTTON / EEPROM ----------------
unsigned long btnPressStart = 0;
bool btnDown = false;

void handleButton() {
  bool pressed = (digitalRead(BUTTON_PIN) == LOW);
  unsigned long now = millis();
  if (pressed && !btnDown) {
    btnDown = true;
    btnPressStart = now;
  } else if (!pressed && btnDown) {

    btnDown = false;
    unsigned long held = now - btnPressStart;
    if (held >= 2000) {

      saveConfigToEEPROM();

      flashRGB(255,255,255);
      delay(80);
      renderRGB(0,0,0,0,false,false);
    } else {
      int next = (int(currentMode) + 1) % 5;
      currentMode = (MODE)next;
    }
  }
}

void saveConfigToEEPROM() {
  EEPROM.update(EE_ADDR_VALID, 0xA5);
  EEPROM.update(EE_ADDR_MODE, (uint8_t)currentMode);
  EEPROM.update(EE_ADDR_PAN, (uint8_t)(maxStepsPan & 0xFF));
  EEPROM.update(EE_ADDR_PAN+1, (uint8_t)((maxStepsPan >> 8) & 0xFF));
  EEPROM.update(EE_ADDR_TILT, (uint8_t)(maxStepsTilt & 0xFF));
  EEPROM.update(EE_ADDR_TILT+1, (uint8_t)((maxStepsTilt >> 8) & 0xFF));
  EEPROM.update(EE_ADDR_GAIN, (uint8_t)constrain((int)(gainRGB*50), 0, 255));
}

void loadConfigFromEEPROM() {
  uint8_t v = EEPROM.read(EE_ADDR_VALID);
  if (v == 0xA5) {
    uint8_t m = EEPROM.read(EE_ADDR_MODE);
    if (m <= 4) currentMode = (MODE)m;
    uint16_t pan = EEPROM.read(EE_ADDR_PAN) | (EEPROM.read(EE_ADDR_PAN+1) << 8);
    uint16_t tilt = EEPROM.read(EE_ADDR_TILT) | (EEPROM.read(EE_ADDR_TILT+1) << 8);
    if (pan >= 64 && pan <= DEFAULT_PAN_STEPS) maxStepsPan = pan;
    if (tilt >= 32 && tilt <= DEFAULT_TILT_STEPS) maxStepsTilt = tilt;
    uint8_t g = EEPROM.read(EE_ADDR_GAIN);
    if (g > 0) gainRGB = constrain(g / 50.0, 0.5, 5.0);
  }
}

ArduRITMICO_V4.png

Así que mire con amor la CNC casera con los nemas 17 y como tengo por ahi el shield cnc del arduino uno (el GRBL v1.1), arranque con una version mas completita...

CSS:
///////////////////////////////////////////////////////////////////////////////////
//  ArduRITMICO v4.1 - Scanner DJ – FFT + NEMA17 + DRV8825 + KY037 (v1.0)
// ETI Patagonia - prof.martintorres@educ.ar - https://github.com/ETI-PATAGONIA-AR
///////////////////////////////////////////////////////////////////////////////////
#include <fix_fft.h>
#include <EEPROM.h>

//-------------------- HARDWARE -------------------
// Micrófono
#define AUDIO_PIN A0             // AO → FFT
#define MIC_DO_PIN 2             // DO → BEAT instantáneo (INT0)
// Botón de modo
#define MODE_BUTTON 3
// RGB MOSFET (PWM)
#define PIN_R 9
#define PIN_G 10
#define PIN_B 11
// CtrlMotores (DRV8825)
#define PAN_STEP 4
#define PAN_DIR 5
#define TILT_STEP 6
#define TILT_DIR 7

// -------------------- CONFIG --------------------
// Parámetros FFT
#define MUESTRAS 128
#define LOGM 7
char dataR[MUESTRAS];
char dataI[MUESTRAS];
unsigned int spectrum[MUESTRAS/2];
// Bandas
#define CUT_BM 7
#define CUT_MA 35
// Variables FFT
unsigned long lastFFT = 0;

// -------------------- MOVIMIENTO --------------------
float centerPan  = 0;
float centerTilt = 0;
int panRange  = 90;   // grados totales (reales: pasos luego)
int tiltRange = 60;
bool modeSinusoidal = true;
unsigned long lastStepPan  = 0;
unsigned long lastStepTilt = 0;
float panPhase  = 0;
float tiltPhase = 0;
// Kick
unsigned long kickPanEnd  = 0;
unsigned long kickTiltEnd = 0;
int kickPanTarget  = 0;
int kickTiltTarget = 0;
// Strobe
unsigned long lastStrobe = 0;
unsigned int strobeLen   = 60;

// -------------------- MODOS --------------------
int modo = 0;
#define MODO_MAX 4
unsigned long lastButton = 0;

// -------------------- BEAT DETECTOR KY037 --------------------
volatile bool beatInstant = false;
unsigned long lastBeatHardware = 0;

void IRAM_ATTR micISR()
    {
     unsigned long t = millis();
     if (t - lastBeatHardware > 40)
       {
        beatInstant = true;
        lastBeatHardware = t;
       }
    }

// -------------------- STEP UTILS --------------------
void stepMotor(int stepPin, int dirPin, bool dir)
  {
  digitalWrite(dirPin, dir);
  digitalWrite(stepPin, HIGH);
  delayMicroseconds(3);
  digitalWrite(stepPin, LOW);
  delayMicroseconds(3);
 }

void moveToAngle(int stepPin, int dirPin, float angleDeg)
   {
    static float lastPanDeg = 0;
    static float lastTiltDeg = 0;
    float &last = (stepPin == PAN_STEP ? lastPanDeg : lastTiltDeg);
    float delta = angleDeg - last;
    last = angleDeg;

  // RELACIÓN PASOS → GRADOS
  // NEMA17 típico: 200 pasos/rev con DRV8825 microstep 1/8 → 1600 steps/rev → 4.44 steps/degree
  const float stepsPerDeg = 4.44;
  long steps = (long)(delta * stepsPerDeg);
  bool d = (steps >= 0);
  steps = abs(steps);

  for (long i = 0; i < steps; i++)
    {
    stepMotor(stepPin, dirPin, d);
    }
  }

// -------------------- RGB --------------------
void rgb(int r, int g, int b)
 {
  analogWrite(PIN_R, r);
  analogWrite(PIN_G, g);
  analogWrite(PIN_B, b);
 }

// -------------------- SETUP --------------------
void setup()
 {
  pinMode(MIC_DO_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), micISR, RISING);
  pinMode(MODE_BUTTON, INPUT_PULLUP);
  pinMode(PIN_R, OUTPUT);
  pinMode(PIN_G, OUTPUT);
  pinMode(PIN_B, OUTPUT);
  pinMode(PAN_STEP, OUTPUT);
  pinMode(PAN_DIR,  OUTPUT);
  pinMode(TILT_STEP, OUTPUT);
  pinMode(TILT_DIR,  OUTPUT);
  rgb(0,0,0);
  delay(400);
}

// -------------------- FFT --------------------
void computeFFT()
 {
  for (int i = 0; i < MUESTRAS; i++)
   {
    int v = analogRead(AUDIO_PIN);
    dataR[i] = (v / 4) - 128;
    dataI[i] = 0;
   }

  fix_fft(dataR, dataI, LOGM, 0);

  for (int i = 0; i < MUESTRAS/2; i++)
   {
    int r = dataR[i];
    int im = dataI[i];
    spectrum[i] = r*r + im*im;
   }
 }

void getBands(unsigned long &bajos, unsigned long &medios, unsigned long &agudos)
 {
  bajos = medios = agudos = 0;

  for (int i=2; i<CUT_BM; i++) bajos += spectrum[i];
  for (int i=CUT_BM; i<CUT_MA; i++) medios += spectrum[i];
  for (int i=CUT_MA; i<MUESTRAS/2; i++) agudos += spectrum[i];
 }

// -------------------- LOOP --------------------
void loop()
  {
  //--------------------------------------------------------
  // 1) Botón de Modo
  //--------------------------------------------------------
  if (digitalRead(MODE_BUTTON) == LOW && millis() - lastButton > 300)
   {
    modo++;
    if (modo > MODO_MAX) modo = 0;
    lastButton = millis();
   }

  //--------------------------------------------------------
  // 2) FFT (cada 8 ms)
  //--------------------------------------------------------
  if (millis() - lastFFT > 8)
   {
    lastFFT = millis();
    computeFFT();
   }

  unsigned long B, M, A;
  getBands(B, M, A);

  float energy = (B + M + A) / 30000.0;
  if (energy > 1.0) energy = 1.0;

  //--------------------------------------------------------
  // 3) Beat detection por FFT (suave)
  //--------------------------------------------------------
  bool beatFFT = (B > 20000 || A > 25000);

  //--------------------------------------------------------
  // 4) Si beat instantáneo por KY037-DO
  //--------------------------------------------------------
  bool beatNow = false;
  if (beatInstant)
   {
    beatInstant = false;
    beatNow = true;
   }

  //--------------------------------------------------------
  // 5) Movimiento PAN y TILT
  //--------------------------------------------------------
  float angPan = centerPan;
  float angTilt = centerTilt;

  // Kick por beat
  if (beatNow)
   {
    kickPanTarget  = random(-panRange/2,  panRange/2);
    kickTiltTarget = random(-tiltRange/2, tiltRange/2);
    kickPanEnd  = millis() + 120;
    kickTiltEnd = millis() + 120;
   }

  if (millis() < kickPanEnd)
   {
    angPan = kickPanTarget;
   }
   else
   {
    if (modo == 0 || modo == 1)
     {
      // suave sinusoidal
      panPhase += 0.035 * energy;
      angPan = (sin(panPhase) * (panRange / 2.0));
     }
     else
     {
      // brusco
      angPan = random(-panRange/2, panRange/2) * energy;
     }
   }

  if (millis() < kickTiltEnd)
   {
    angTilt = kickTiltTarget;
   }
    else
   {
    if (modo == 0 || modo == 2)
     {
      tiltPhase += 0.045 * energy;
      angTilt = (sin(tiltPhase) * (tiltRange / 2.0));
     }
     else
     {
      angTilt = random(-tiltRange/2, tiltRange/2) * energy;
     }
   }

  moveToAngle(PAN_STEP, PAN_DIR, angPan);
  moveToAngle(TILT_STEP, TILT_DIR, angTilt);

  //--------------------------------------------------------
  // 6) RGB según modo
  //--------------------------------------------------------
  if (modo == 3)
   {
    // STROBE
    if (beatNow || beatFFT)
     {
      rgb(255,255,255);
      lastStrobe = millis();
     }
    if (millis() - lastStrobe > strobeLen) rgb(0,0,0);
   }
  else if (modo == 4)
   {
    // COLOR DINÁMICO
    int r = min(255, (int)(A / 250));
    int g = min(255, (int)(M / 250));
    int b = min(255, (int)(B / 250));
    rgb(r,g,b);
   }
  else
   {
    // COLOR por bandas
    int r = min(255, (int)(A / 300));
    int g = min(255, (int)(M / 300));
    int b = min(255, (int)(B / 300));
    rgb(r,g,b);
   }
}

Despues de mirar nuevamente algunos aportes en el topico, edite y mejore un poco en una segunda version (la v4.2i):

CSS:
/*/////////////////////////////////////////////////////////////////////////////////
//  ArduRITMICO v4.2 - Scanner DJ – FFT + NEMA17 + DRV8825 + KY037 (v1.0)
// ETI Patagonia - prof.martintorres@educ.ar - https://github.com/ETI-PATAGONIA-AR
///////////////////////////////////////////////////////////////////////////////////

  Hardware:
  - Arduino UNO
  - Shield CNC (GRBL V1.1)
  - Driver DRV8825
  - Motores Nema 17
  - PAN (Eje X) STEP = pin D2, DIR = Pin D5
  - TILT (Eje Y) STEP = Pin D3, DIR = Pin D6
  - ENABLE (todos los drivers) = Pin D8 (LOW = habilitado)
  - Micrófono KY-037 AO -> Pin A0 (para FFT)
  - POT1 Pin A1 -> velocidad / agresividad
  - POT2 Pin A2 -> límite de PAN (grados)
  - POT3 Pin A3 -> límite de TILT (grados)
  - MOSFET RGB: Pin D9 (R), Pin D10 (G), Pin D11 (B)  (low-side)
  - Botón de modos: Pin D12 (INPUT_PULLUP → al presionarse va a GND)
  - OLED I2C: Pin A4 SDA, Pin A5 SCL (SSD1306 128x32)
  - Librerías usadas: fix_fft, AccelStepper, Adafruit_SSD1306, Adafruit_GFX
  y creo que no se me esta olvidando nada...
*/

#include <fix_fft.h>
#include <AccelStepper.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// ---------------------------- CONFIG HARDWARE ----------------------------
#define PAN_STEP 2
#define PAN_DIR  5
#define TILT_STEP 3
#define TILT_DIR  6
#define ENABLE_DRV 8
#define AUDIO_PIN A0
#define POT_SPEED A1
#define POT_PAN_LIMIT A2
#define POT_TILT_LIMIT A3
#define RGB_R 9
#define RGB_G 10
#define RGB_B 11
#define BTN_MODE 12
// OLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// ---------------------------- FFT / AUDIO ----------------------------
#define MUESTRAS 128
#define LOGM 7
#define BIN_OFFSET 2
char vReal[MUESTRAS];
char vImag[MUESTRAS];
unsigned long magn[MUESTRAS/2];
// Valor máximo esperado de energía FFT (ajustable si satura)
const unsigned long MAX_MAGN_EXPECTED = 20000UL;
// Límites de bandas (bajos, medios, agudos)
int binBMaxDefault = 7;
int binMMaxDefault = 35;
// Suavizados (EMA)
double smoothB = 0, smoothM = 0, smoothA = 0;

// ---------------------------- MOTORES ----------------------------
AccelStepper stepperPan(AccelStepper::DRIVER, PAN_STEP, PAN_DIR);
AccelStepper stepperTilt(AccelStepper::DRIVER, TILT_STEP, TILT_DIR);
// Config de motores
const int STEPPER_FULL_STEP = 200; // 1.8°
int microstep = 16; // DRV8825 configurado con jumpers
long stepsPerRev = STEPPER_FULL_STEP * microstep;
// Límites de movimiento según grados
long defaultPanSteps = (stepsPerRev * 180L) / 360L;
long defaultTiltSteps = (stepsPerRev * 90L) / 360L;
long maxPanSteps = defaultPanSteps;
long maxTiltSteps = defaultTiltSteps;
// centro en 0 (posición virtual)
long centerPan = 0;
long centerTilt = 0;
// Fases para el movimiento sinusoidal
double phasePan = 0;
double phaseTilt = 0;
double basePhaseInc = 0.02;
// "Patadas" de movimiento para el modo BRUSCO
int kickPanBase = 300;
int kickTiltBase = 200;
int kickDecayMs = 120;
long kickTargetPan = 0;
unsigned long kickEndPan = 0;
long kickTargetTilt = 0;
unsigned long kickEndTilt = 0;

// ---------------------------- MODOS ----------------------------
enum MODE { MODE_SIN = 0, MODE_BRUSCO = 1, MODE_AUDIO = 2 };
MODE currentMode = MODE_SIN;

// ---------------------------- BOTÓN ----------------------------
unsigned long lastButtonMillis = 0;
bool lastButtonState = HIGH;
const unsigned long debounceMs = 50;

// ---------------------------- STROBE ----------------------------
unsigned long lastStrobeMillis = 0;
int strobeLenMs = 40;
int strobeThresholdFactor = 160; // fuerza necesaria de agudos

// ---------------------------- TIMERS ----------------------------
unsigned long lastFFTMillis = 0;
const unsigned long fftIntervalMs = 8;
unsigned long loopDelay = 4;
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
void setup() {

  Serial.begin(115200);
  //Serial.println("Iniciando ScannerDJ...");
  // OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("OLED no detectado");
  } else {
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
  }
  // Pines
  pinMode(ENABLE_DRV, OUTPUT);
  digitalWrite(ENABLE_DRV, LOW); // habilitar drivers
  pinMode(RGB_R, OUTPUT);
  pinMode(RGB_G, OUTPUT);
  pinMode(RGB_B, OUTPUT);
  analogWrite(RGB_R, 0);
  analogWrite(RGB_G, 0);
  analogWrite(RGB_B, 0);
  pinMode(BTN_MODE, INPUT_PULLUP);
  // Motores – velocidad y aceleración muy altas
  stepperPan.setMaxSpeed(6000.0);
  stepperPan.setAcceleration(40000.0);
  stepperTilt.setMaxSpeed(5000.0);
  stepperTilt.setAcceleration(35000.0);
  stepperPan.setCurrentPosition(0);
  stepperTilt.setCurrentPosition(0);
  randomSeed(analogRead(A3));
  // Pantalla de inicio
  display.clearDisplay();
  display.setCursor(0,0);
  display.println("ScannerDJ");
  display.println("Modo: Sinusoidal");
  display.display();
  delay(400);
}
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
// ---------------------------- FUNCIONES DE FFT ----------------------------
// Ventana hanning
void applyWindow(char *data) {
  double n1 = double(MUESTRAS) - 1.0;
  for (int i = 0; i < MUESTRAS/2; i++) {
    double r = double(i) / n1;
    double w = 0.5 * (1.0 - cos(6.2831853 * r));
    data[i] = (char)(data[i] * w);
    data[MUESTRAS - 1 - i] = (char)(data[MUESTRAS - 1 - i] * w);
  }
}

// Ejecutar FFT completa
void computeFFT() {

  // Tomar muestras
  for (int i = 0; i < MUESTRAS; i++) {
    int raw = analogRead(AUDIO_PIN);
    int v = raw / 4 - 128;
    v = constrain(v, -128, 127);
    vReal[i] = (char)v;
    vImag[i] = 0;
  }

  // Ventana
  applyWindow(vReal);

  // FFT
  fix_fft(vReal, vImag, LOGM, 0);

  // Magnitudes
  for (int b = 0; b < MUESTRAS/2; b++) {
    int re = vReal[b];
    int im = vImag[b];
    magn[b] = (unsigned long)(re * re) + (unsigned long)(im * im);
  }
}

// Suma de una banda FFT
unsigned long sumBand(int fromBin, int toBin) {
  unsigned long s = 0;
  for (int b = fromBin; b <= toBin && b < MUESTRAS/2; b++) s += magn[b];
  return s;
}

// ---------------------------- RGB ----------------------------
void renderRGB(double normB, double normM, double normA, bool beatB, bool beatA, bool strobeNow) {

  // Si hay strobe → blanco total
  if (strobeNow) {
    analogWrite(RGB_R, 255);
    analogWrite(RGB_G, 255);
    analogWrite(RGB_B, 255);
    return;
  }

  // Agudos → rojo
  // Medios → verde
  // Bajos → azul
  uint8_t R = normA * 255.0;
  uint8_t G = normM * 255.0;
  uint8_t B = normB * 255.0;

  // Más brillo si hay beats
  if (beatB) B = min(255, B + 120);
  if (beatA) R = min(255, R + 120);

  analogWrite(RGB_R, R);
  analogWrite(RGB_G, G);
  analogWrite(RGB_B, B);
}

// ---------------------------- UTILIDADES ÁNGULOS ----------------------------
double stepsPerDegree() {
  return double(stepsPerRev) / 360.0;
}

long degToStepPan(double deg) {
  return centerPan + (deg * stepsPerDegree());
}

long degToStepTilt(double deg) {
  return centerTilt + (deg * stepsPerDegree());
}

// ---------------------------- BOTÓN ----------------------------
void handleButton() {

  bool raw = digitalRead(BTN_MODE);
  unsigned long now = millis();

  if (raw != lastButtonState) lastButtonMillis = now;

  if ((now - lastButtonMillis) > debounceMs) {
    if (raw == LOW && lastButtonState == HIGH) {

      int nm = currentMode + 1;
      if (nm > MODE_AUDIO) nm = MODE_SIN;
      currentMode = (MODE)nm;

      // Blink de confirmación
      for (int i = 0; i < 2; i++) {
        analogWrite(RGB_R,255); analogWrite(RGB_G,255); analogWrite(RGB_B,255); delay(80);
        analogWrite(RGB_R,0); analogWrite(RGB_G,0); analogWrite(RGB_B,0); delay(60);
      }

      // Mostrar en OLED
      display.clearDisplay();
      display.setCursor(0,0);
      display.print("Modo: ");
      if (currentMode == MODE_SIN) display.println("Sinusoidal");
      else if (currentMode == MODE_BRUSCO) display.println("Brusco");
      else display.println("Audio");
      display.display();

      delay(200);
    }
  }

  lastButtonState = raw;
}
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
void loop() {

  unsigned long now = millis();

  // Leer potenciómetros
  int potSpeed = analogRead(POT_SPEED);
  int potPan = analogRead(POT_PAN_LIMIT);
  int potTilt = analogRead(POT_TILT_LIMIT);

  // Parámetros derivados
  double speedFactor = map(potSpeed, 0, 1023, 20, 400) / 100.0;
  int panDegreesMax = map(potPan, 0, 1023, 30, 180);
  int tiltDegreesMax = map(potTilt, 0, 1023, 10, 90);

  maxPanSteps = (panDegreesMax / 360.0) * stepsPerRev;
  maxTiltSteps = (tiltDegreesMax / 360.0) * stepsPerRev;

  // FFT cada cierto tiempo
  if (now - lastFFTMillis > fftIntervalMs) {

    lastFFTMillis = now;

    computeFFT();

    unsigned long sumB = sumBand(BIN_OFFSET, binBMaxDefault);
    unsigned long sumM = sumBand(binBMaxDefault+1, binMMaxDefault);
    unsigned long sumA = sumBand(binMMaxDefault+1, (MUESTRAS/2)-1);

    // Suavizado EMA
    smoothB = smoothB * 0.75 + sumB * 0.25;
    smoothM = smoothM * 0.75 + sumM * 0.25;
    smoothA = smoothA * 0.75 + sumA * 0.25;

    // Normalizar
    double normB = constrain((double)sumB / MAX_MAGN_EXPECTED * speedFactor, 0.0, 1.0);
    double normM = constrain((double)sumM / MAX_MAGN_EXPECTED * speedFactor, 0.0, 1.0);
    double normA = constrain((double)sumA / MAX_MAGN_EXPECTED * speedFactor, 0.0, 1.0);

    bool beatB = (sumB > smoothB * 1.6);
    bool beatA = (sumA > smoothA * 1.6);

    bool strobeNow = false;
    if (currentMode == MODE_BRUSCO && (sumA > (unsigned long)strobeThresholdFactor * 100)) {
      strobeNow = true;
      lastStrobeMillis = now;
    }

    // Si hay beat, generar patadas
    if (beatB) {
      kickTargetTilt = (random(0,2)?1:-1) * (kickTiltBase + normB * kickTiltBase);
      kickEndTilt = now + kickDecayMs;
    }
    if (beatA) {
      kickTargetPan = (random(0,2)?1:-1) * (kickPanBase + normA * kickPanBase);
      kickEndPan = now + kickDecayMs;
    }

    // Movimiento según modo
    long targetPanSteps = centerPan;
    long targetTiltSteps = centerTilt;

    double totalEnergy = (normB + normM + normA) / 3.0;
    if (totalEnergy < 0.01) totalEnergy = 0.0;

    // ---------- MODO 1: Sinusoidal suave ----------
    if (currentMode == MODE_SIN) {

      phasePan += basePhaseInc * (0.5 + speedFactor * 1.5);
      phaseTilt += basePhaseInc * (0.7 + speedFactor * 1.3);

      double ampPanDeg = panDegreesMax/2.0 * max(0.25, totalEnergy + 0.2);
      double ampTiltDeg = tiltDegreesMax/2.0 * max(0.25, totalEnergy + 0.2);

      double panDeg = sin(phasePan) * ampPanDeg;
      double tiltDeg = sin(phaseTilt) * ampTiltDeg;

      targetPanSteps = degToStepPan(panDeg);
      targetTiltSteps = degToStepTilt(tiltDeg);
    }

    // ---------- MODO 2: BRUSCO ----------
    else if (currentMode == MODE_BRUSCO) {

      if (now < kickEndPan) targetPanSteps = centerPan + kickTargetPan;
      else targetPanSteps = centerPan + random(-20,21) * speedFactor;

      if (now < kickEndTilt) targetTiltSteps = centerTilt + kickTargetTilt;
      else targetTiltSteps = centerTilt + random(-12,13) * speedFactor;
    }

    // ---------- MODO 3: AUDIO REACTIVO ----------
    else {

      double panDeg = mapDouble(normB, 0.0, 1.0, -panDegreesMax/2.0, panDegreesMax/2.0);
      double tiltDeg = mapDouble(normM, 0.0, 1.0, -tiltDegreesMax/2.0, tiltDegreesMax/2.0);

      // movimiento suave adicional
      phasePan += basePhaseInc * 0.5;
      phaseTilt += basePhaseInc * 0.6;
      panDeg += sin(phasePan) * (panDegreesMax * 0.05);
      tiltDeg += sin(phaseTilt) * (tiltDegreesMax * 0.05); // ← CORREGIDO

      targetPanSteps = degToStepPan(panDeg);
      targetTiltSteps = degToStepTilt(tiltDeg);
    }

    // Aplicar límites mecánicos
    long panLimit = maxPanSteps;
    long tiltLimit = maxTiltSteps;

    targetPanSteps = constrain(targetPanSteps, centerPan - panLimit, centerPan + panLimit);
    targetTiltSteps = constrain(targetTiltSteps, centerTilt - tiltLimit, centerTilt + tiltLimit);

    // Enviar movimiento
    stepperPan.moveTo(targetPanSteps);
    stepperTilt.moveTo(targetTiltSteps);

    // LED RGB
    renderRGB(normB, normM, normA, beatB, beatA, strobeNow);
  }

  // Ejecutar motores
  stepperPan.run();
  stepperTilt.run();

  // Botón
  handleButton();

  // Actualizar OLED cada 200 ms
  static unsigned long lastOled = 0;
  if (now - lastOled > 200) {
    lastOled = now;
    drawOLED(currentMode, potSpeed, potPan, potTilt);
  }

  delay(loopDelay);
}
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
// ---------------------------- FUNCIONES EXTRA ----------------------------
double mapDouble(double x, double in_min, double in_max, double out_min, double out_max) {
  if (x <= in_min) return out_min;
  if (x >= in_max) return out_max;
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

void drawOLED(MODE m, int potSpeed, int potPan, int potTilt) {

  display.clearDisplay();
  display.setCursor(0,0);

  display.print("Modo: ");
  if (m == MODE_SIN) display.println("Sinusoidal");
  else if (m == MODE_BRUSCO) display.println("Brusco");
  else display.println("Audio");

  int spdPct = map(potSpeed, 0, 1023, 0, 100);
  int panDeg = map(potPan, 0, 1023, 30, 180);
  int tiltDeg = map(potTilt, 0, 1023, 10, 90);

  display.print("SPD:");
  display.print(spdPct);
  display.print("% ");

  display.print("PAN:");
  display.print(panDeg);

  display.print(" TLT:");
  display.println(tiltDeg);

  display.display();
}
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

Me iba a poner armar el hardware y los driver los tengo en el rap con el mega2550, sumado a que me dio fiaca armar la etapa de los mosfet para el rgb... Veo si en la semana encierro a flojera en un cuarto y me pongo a jugar en el armado... por lo menos con la parte de los PAP y la pantalla... Si ven errores o quieren modificarlos, metan mano y propongan
 
Última edición:
Bueno, arme 7 versiones distintas con el driver uln2003 y el motor 28BYJ-48 y no me termino de convencer...
Que complejo que es todo, no se ni papá, yo estuve todo el día de ayer para hacer círculos y encima me quedo chueco . A ver que te puedo robar. Ya me decidí. Paso a paso y halógena en dos de los scaner.
Y en los otros dos vuelan los globos y pruebo con los módulos Neopixel ring rgb. Uno círculo chico , debajo de la lente y otro por fuera del scaner, rodeando la lente junto debajo del espejo .
Estoy viendo unos colimadores de 8° pero no tengo idea como quedará el haz. Me da miedo comprarlo y que después se vean puntitos chiquitos.
Cuando los tenga en mi poder tal vez me puedas ayudar con la escena de los leds . Y bueno, justo esos pap con los drivers 2003 son los que pedí para el disco de colores ... Solo ruego que sea compatible el eje con el disco de gobos.. por ahora solo tengo DC no puedo robarte nada.
 
Atrás
Arriba