Close

Pulsadores Arcade efecto Hall 2

A project log for THE ULTIMATE MINI ARCADE

Classic arcade with all the latest technological advancements, ready for the classics. Enjoy!

srrubioSrRubio 03/30/2026 at 10:190 Comments

He estado haciendo muchas pruebas en el diseño del pulsador. He partido de un pulsador de 24mm que he modificado para adaptar el sensor, muelle y demás.

El problema ha sido el rozamiento y el guiado.

 Al final he llegado a un diseño entre pulsador arcade y pedal. A falta de mejorar o no las conexiones, ya lo he terminado.

También es importante el material y la orientación de la impresión. Puesto que si no se realiza bien, el material se puede partir.

He usado PETG para la base y he estado probando con PLA en el pulsador con buenos resultados. A falta de últimas pruebas ya ya veo el final de este mini proyecto.

https://vm.tiktok.com/ZNRCdyoyw/

En cuanto a la programación, he seguido usando la librería xinput pero añadiendo autocalibración, efecto pedal..

#include <XInput.h>  // Librería para emular mando Xbox por USB


// ================= CONFIG =================

// Resolución del ADC (10 bits: 0–1023)
const int ADC_Max = 1023;


// ===== Pines de triggers (sensores Hall) =====
const int Pin_TriggerL = A2;
const int Pin_TriggerR = A3;


// ===== Pines de botones =====
const int Pin_ButtonA = 0;
const int Pin_ButtonB = 1;
const int Pin_ButtonX = 2;
const int Pin_ButtonY = 3;
const int Pin_ButtonLB = 4;
const int Pin_ButtonRB = 5;
const int Pin_ButtonBack  = 6;
const int Pin_ButtonStart = 7;
const int Pin_ButtonL3 = 8;
const int Pin_ButtonR3 = 9;


// ===== D-Pad =====
const int Pin_DpadUp    = 10;
const int Pin_DpadDown  = 11;
const int Pin_DpadLeft  = 12;
const int Pin_DpadRight = 13;


// ===== FILTRO (suaviza la señal analógica) =====

// Valores filtrados (estado interno)
float filteredL = 0;
float filteredR = 0;

// Factor de suavizado:
// 0.1 = muy suave (más retardo)
// 0.3 = más rápido (menos suavizado)
const float alpha = 0.2;


// ===== AUTO-CALIBRACIÓN =====

// Inicializamos extremos "imposibles"
// Se irán ajustando automáticamente en uso
int minL = 1023;
int maxL = 0;

int minR = 1023;
int maxR = 0;


// ================= SETUP =================

void setup() {

  Serial.begin(115200);  // Comunicación serie para debug

  // Configura el rango de los triggers (0–1023)
  XInput.setTriggerRange(0, ADC_Max);

  // Desactiva envío automático (control manual con XInput.send())
  XInput.setAutoSend(false);


  // Configura todos los botones como entrada con pull-up interno
  // -> estado normal = HIGH
  // -> pulsado = LOW
  pinMode(Pin_ButtonA, INPUT_PULLUP);
  pinMode(Pin_ButtonB, INPUT_PULLUP);
  pinMode(Pin_ButtonX, INPUT_PULLUP);
  pinMode(Pin_ButtonY, INPUT_PULLUP);
  pinMode(Pin_ButtonLB, INPUT_PULLUP);
  pinMode(Pin_ButtonRB, INPUT_PULLUP);
  pinMode(Pin_ButtonBack, INPUT_PULLUP);
  pinMode(Pin_ButtonStart, INPUT_PULLUP);
  pinMode(Pin_ButtonL3, INPUT_PULLUP);
  pinMode(Pin_ButtonR3, INPUT_PULLUP);

  pinMode(Pin_DpadUp, INPUT_PULLUP);
  pinMode(Pin_DpadDown, INPUT_PULLUP);
  pinMode(Pin_DpadLeft, INPUT_PULLUP);
  pinMode(Pin_DpadRight, INPUT_PULLUP);


  delay(1000);  // Espera para estabilizar sensores Hall


  // Inicializa los filtros con el valor actual
  // Evita saltos bruscos al arrancar
  filteredL = analogRead(Pin_TriggerL);
  filteredR = analogRead(Pin_TriggerR);


  // Inicia el dispositivo XInput
  XInput.begin();
}


// ================= LOOP =================

void loop() {

  // ===== BOTONES =====
  // Se invierte la lectura (!)
  // porque INPUT_PULLUP: LOW = pulsado

  XInput.setButton(BUTTON_A, !digitalRead(Pin_ButtonA));
  XInput.setButton(BUTTON_B, !digitalRead(Pin_ButtonB));
  XInput.setButton(BUTTON_X, !digitalRead(Pin_ButtonX));
  XInput.setButton(BUTTON_Y, !digitalRead(Pin_ButtonY));

  XInput.setButton(BUTTON_LB, !digitalRead(Pin_ButtonLB));
  XInput.setButton(BUTTON_RB, !digitalRead(Pin_ButtonRB));

  XInput.setButton(BUTTON_BACK,  !digitalRead(Pin_ButtonBack));
  XInput.setButton(BUTTON_START, !digitalRead(Pin_ButtonStart));

  XInput.setButton(BUTTON_L3, !digitalRead(Pin_ButtonL3));
  XInput.setButton(BUTTON_R3, !digitalRead(Pin_ButtonR3));


  // ===== D-PAD =====
  // Envía las 4 direcciones a la vez
  XInput.setDpad(
    !digitalRead(Pin_DpadUp),
    !digitalRead(Pin_DpadDown),
    !digitalRead(Pin_DpadLeft),
    !digitalRead(Pin_DpadRight)
  );


  // ===== TRIGGERS =====

  // Lectura directa del sensor Hall (sin procesar)
  int rawL = analogRead(Pin_TriggerL);
  int rawR = analogRead(Pin_TriggerR);


  // ---- FILTRO (suaviza vibraciones y ruido) ----
  filteredL = alpha * rawL + (1 - alpha) * filteredL;
  filteredR = alpha * rawR + (1 - alpha) * filteredR;


  // ---- AUTO-CALIBRACIÓN ----
  // Detecta automáticamente mínimo y máximo reales

  if (filteredL < minL) minL = filteredL;
  if (filteredL > maxL) maxL = filteredL;

  if (filteredR < minR) minR = filteredR;
  if (filteredR > maxR) maxR = filteredR;


  // ---- NORMALIZACIÓN ----
  // Convierte el rango real -> 0.0 a 1.0

  float normL = 0;
  float normR = 0;

  // Evita división por cero
  if (maxL > minL + 5) {
    normL = (filteredL - minL) / (float)(maxL - minL);
  }

  if (maxR > minR + 5) {
    normR = (filteredR - minR) / (float)(maxR - minR);
  }

  // Limita valores al rango válido
  normL = constrain(normL, 0.0, 1.0);
  normR = constrain(normR, 0.0, 1.0);


  // ---- CURVA TIPO GATILLO ----
  // Hace el inicio suave y el final más progresivo
  // Ajustable: 1.5–2.2 según sensaciones

  normL = pow(normL, 1.8);
  normR = pow(normR, 1.8);


  // ---- ESCALADO FINAL ----
  // Convierte 0.0–1.0 -> 0–1023

  int triggerLeft  = normL * 1023;
  int triggerRight = normR * 1023;


  // ---- ENVÍO A XINPUT ----
  XInput.setTrigger(TRIGGER_LEFT, triggerLeft);
  XInput.setTrigger(TRIGGER_RIGHT, triggerRight);


  // ===== DEBUG OPCIONAL =====
  /*
  Serial.print("L raw:");
  Serial.print(rawL);
  Serial.print(" min:");
  Serial.print(minL);
  Serial.print(" max:");
  Serial.print(maxL);
  Serial.print(" out:");
  Serial.print(triggerLeft);

  Serial.print(" | R raw:");
  Serial.print(rawR);
  Serial.print(" min:");
  Serial.print(minR);
  Serial.print(" max:");
  Serial.print(maxR);
  Serial.print(" out:");
  Serial.println(triggerRight);
  */


  // Envía todos los datos al PC
  XInput.send();
} 

Discussions