Ven a vernos
Ronda del Caballero de La Mancha 67
Horario
Lunes - Viernes: 8:00 a 21:00

Encoder

<div style="font-family: Arial, sans-serif; text-align: center; background: #f5f8fa; padding: 30px;"> <h1 style="color: #007bff;">Velocímetro con acelerómetro 📱</h1> <div style="font-size: 1.5em; margin: 10px 0;">Velocidad X: <span id="vx">0</span> m/s</div> <div style="font-size: 1.5em; margin: 10px 0;">Velocidad Y: <span id="vy">0</span> m/s</div> <div style="font-size: 1.5em; margin: 10px 0;">Velocidad Z: <span id="vz">0</span> m/s</div> <div style="font-size: 1.5em; margin: 10px 0;"><strong>Velocidad Máxima: <span id="vmax">0</span> m/s</strong></div> <button id="startBtn" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Iniciar medición</button> <button id="resetBtn" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Reiniciar</button> <div id="status" style="color: #555; margin-top: 15px; font-size: 0.9em;">⏸ Aún no iniciado</div> </div> <p><script> let lastTimestamp = null; let vx = 0, vy = 0, vz = 0; let vmax = 0; let gx = 0, gy = 0, gz = 0; const alpha = 0.8; const statusEl = document.getElementById("status"); function setStatus(msg) { statusEl.textContent = msg; console.log(msg); } function updateDisplay() { document.getElementById("vx").textContent = vx.toFixed(2); document.getElementById("vy").textContent = vy.toFixed(2); document.getElementById("vz").textContent = vz.toFixed(2); document.getElementById("vmax").textContent = vmax.toFixed(2); } function resetValues() { vx = vy = vz = vmax = 0; gx = gy = gz = 0; lastTimestamp = null; updateDisplay(); setStatus("🔄 Reiniciado"); } function startMotion() { if (typeof DeviceMotionEvent === 'undefined') { setStatus("❌ Tu navegador no soporta DeviceMotionEvent."); return; } // iOS (por compatibilidad futura) o Android modernos if (typeof DeviceMotionEvent.requestPermission === 'function') { DeviceMotionEvent.requestPermission() .then(response => { if (response === 'granted') { setStatus("✅ Permiso concedido. Mueve el móvil."); window.addEventListener('devicemotion', motionHandler); } else { setStatus("❌ Permiso denegado: " + response); } }) .catch(err => setStatus("⚠️ Error solicitando permiso: " + err)); } else { // Android normalmente entra aquí setStatus("✅ Sensor activado. Mueve el móvil."); window.addEventListener('devicemotion', motionHandler); } } function motionHandler(event) { const acc = event.accelerationIncludingGravity; const ts = event.timeStamp; if (!acc) { setStatus("⚠️ No se reciben datos de aceleración"); return; } if (lastTimestamp === null) { lastTimestamp = ts; return; } // Filtro pasa-alto para quitar gravedad gx = alpha * gx + (1 - alpha) * acc.x; gy = alpha * gy + (1 - alpha) * acc.y; gz = alpha * gz + (1 - alpha) * acc.z; const ax = acc.x - gx; const ay = acc.y - gy; const az = acc.z - gz; const dt = (ts - lastTimestamp) / 1000; lastTimestamp = ts; vx += ax * dt; vy += ay * dt; vz += az * dt; const maxAxis = Math.max(Math.abs(vx), Math.abs(vy), Math.abs(vz)); if (maxAxis > vmax) vmax = maxAxis; updateDisplay(); } document.getElementById('startBtn').addEventListener('click', startMotion); document.getElementById('resetBtn').addEventListener('click', resetValues); </script></p>

Enplo

<div id="encoder-motionis" style="font-family: Arial, sans-serif; text-align: center; background: #f5f8fa; padding: 30px;"> <h1 style="color:#007BFF;">Encoder de velocidad 📊</h1> <div style="font-size: 1.5em; margin: 10px 0;"> Velocidad actual: <span id="velocidad">0.00</span> m/s </div> <div style="font-size: 2em; margin: 10px 0;"> 🏁 <strong>Velocidad Máxima: <span id="vmax">0.00</span> m/s</strong> </div> <button id="startBtn" type="button" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Iniciar</button> <button id="resetBtn" type="button" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Reiniciar</button> <div id="status" style="color:#555; margin-top: 15px; font-size: 0.9em;">⏸ Aún no iniciado</div> </div> <script> // Esperamos a que la página cargue completamente (importante en WordPress) document.addEventListener('DOMContentLoaded', function () { let lastTimestamp = null; let velocidad = 0; let vmax = 0; let gz = 0; const alpha = 0.8; const UMBRAL_ACEL = 0.2; const velSpan = document.getElementById("velocidad"); const vmaxSpan = document.getElementById("vmax"); const statusEl = document.getElementById("status"); const startBtn = document.getElementById("startBtn"); const resetBtn = document.getElementById("resetBtn"); function setStatus(msg) { statusEl.textContent = msg; console.log(msg); } function updateDisplay() { velSpan.textContent = velocidad.toFixed(2); vmaxSpan.textContent = vmax.toFixed(2); } function resetValues() { velocidad = 0; vmax = 0; gz = 0; lastTimestamp = null; updateDisplay(); setStatus("🔄 Reiniciado"); } function startMotion() { if (typeof DeviceMotionEvent === 'undefined') { setStatus("❌ Tu navegador no soporta DeviceMotionEvent."); return; } // Android: no necesita permisos normalmente if (typeof DeviceMotionEvent.requestPermission === 'function') { DeviceMotionEvent.requestPermission() .then(response => { if (response === 'granted') { setStatus("✅ Sensor activado. Coloca el móvil sobre la carga."); window.addEventListener('devicemotion', motionHandler); } else { setStatus("❌ Permiso denegado: " + response); } }) .catch(err => setStatus("⚠️ Error: " + err)); } else { setStatus("✅ Sensor activado. Coloca el móvil sobre la carga."); window.addEventListener('devicemotion', motionHandler); } } function motionHandler(event) { const acc = event.accelerationIncludingGravity; const ts = event.timeStamp; if (!acc) return; if (lastTimestamp === null) { lastTimestamp = ts; return; } // Filtro pasa-alto para eliminar la gravedad gz = alpha * gz + (1 - alpha) * acc.z; const az = acc.z - gz; const dt = (ts - lastTimestamp) / 1000; lastTimestamp = ts; // Integramos solo si hay movimiento real if (Math.abs(az) > UMBRAL_ACEL) { velocidad += az * dt; if (Math.abs(velocidad) > vmax) vmax = Math.abs(velocidad); } else { // Reducción de deriva cuando está en reposo velocidad *= 0.98; } updateDisplay(); } startBtn.addEventListener('click', startMotion); resetBtn.addEventListener('click', resetValues); }); </script>

Enco

<div id="encoder-motionis" style="font-family: Arial, sans-serif; text-align: center; background: #f5f8fa; padding: 30px;"> <h1 style="color:#007BFF;">Encoder de velocidad 📊</h1> <div style="font-size: 1.5em; margin: 10px 0;"> Velocidad actual: <span id="velocidad">0.00</span> m/s </div> <div style="font-size: 2em; margin: 10px 0;"> 🏁 <strong>Velocidad Máxima: <span id="vmax">0.00</span> m/s</strong> </div> <button id="startBtn" type="button" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Iniciar</button> <button id="resetBtn" type="button" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Reiniciar</button> <div id="status" style="color:#555; margin-top: 15px; font-size: 0.9em;">⏸ Aún no iniciado</div> </div> <script> // Esperamos a que la página cargue completamente (importante en WordPress) document.addEventListener('DOMContentLoaded', function () { let lastTimestamp = null; let velocidad = 0; let vmax = 0; let gz = 0; const alpha = 0.8; const UMBRAL_ACEL = 0.2; const velSpan = document.getElementById("velocidad"); const vmaxSpan = document.getElementById("vmax"); const statusEl = document.getElementById("status"); const startBtn = document.getElementById("startBtn"); const resetBtn = document.getElementById("resetBtn"); function setStatus(msg) { statusEl.textContent = msg; console.log(msg); } function updateDisplay() { velSpan.textContent = velocidad.toFixed(2); vmaxSpan.textContent = vmax.toFixed(2); } function resetValues() { velocidad = 0; vmax = 0; gz = 0; lastTimestamp = null; updateDisplay(); setStatus("🔄 Reiniciado"); } function startMotion() { if (typeof DeviceMotionEvent === 'undefined') { setStatus("❌ Tu navegador no soporta DeviceMotionEvent."); return; } // Android: no necesita permisos normalmente if (typeof DeviceMotionEvent.requestPermission === 'function') { DeviceMotionEvent.requestPermission() .then(response => { if (response === 'granted') { setStatus("✅ Sensor activado. Coloca el móvil sobre la carga."); window.addEventListener('devicemotion', motionHandler); } else { setStatus("❌ Permiso denegado: " + response); } }) .catch(err => setStatus("⚠️ Error: " + err)); } else { setStatus("✅ Sensor activado. Coloca el móvil sobre la carga."); window.addEventListener('devicemotion', motionHandler); } } function motionHandler(event) { const acc = event.accelerationIncludingGravity; const ts = event.timeStamp; if (!acc) return; if (lastTimestamp === null) { lastTimestamp = ts; return; } // Filtro pasa-alto para eliminar la gravedad gz = alpha * gz + (1 - alpha) * acc.z; const az = acc.z - gz; const dt = (ts - lastTimestamp) / 1000; lastTimestamp = ts; // Integramos solo si hay movimiento real if (Math.abs(az) > UMBRAL_ACEL) { velocidad += az * dt; if (Math.abs(velocidad) > vmax) vmax = Math.abs(velocidad); } else { // Reducción de deriva cuando está en reposo velocidad *= 0.98; } updateDisplay(); } startBtn.addEventListener('click', startMotion); resetBtn.addEventListener('click', resetValues); }); </script>

EMo

<div id="encoder-motionis" style="font-family: Arial, sans-serif; text-align: center; background: #f5f8fa; padding: 30px;"> <h1 style="color:#007BFF;">Encoder de velocidad 📊</h1> <div style="font-size: 1.5em; margin: 10px 0;"> Velocidad actual: <span id="velocidad">0.00</span> m/s </div> <div style="font-size: 2em; margin: 10px 0;"> 🏁 <strong>Velocidad Máxima: <span id="vmax">0.00</span> m/s</strong> </div> <button id="startBtn" type="button" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Iniciar</button> <button id="resetBtn" type="button" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Reiniciar</button> <div id="status" style="color:#555; margin-top: 15px; font-size: 0.9em;">⏸ Aún no iniciado</div> </div> <script> document.addEventListener('DOMContentLoaded', function () { let lastTimestamp = null; let velocidad = 0; let vmax = 0; let gz = 0; const alpha = 0.8; const UMBRAL_ACEL = 0.2; const VMIN_RESET = 0.05; // debajo de esto consideramos que la barra se detuvo const velSpan = document.getElementById("velocidad"); const vmaxSpan = document.getElementById("vmax"); const statusEl = document.getElementById("status"); const startBtn = document.getElementById("startBtn"); const resetBtn = document.getElementById("resetBtn"); function setStatus(msg) { statusEl.textContent = msg; console.log(msg); } function updateDisplay() { velSpan.textContent = velocidad.toFixed(2); vmaxSpan.textContent = vmax.toFixed(2); } function resetValues() { velocidad = 0; vmax = 0; gz = 0; lastTimestamp = null; updateDisplay(); setStatus("🔄 Reiniciado"); } function startMotion() { if (typeof DeviceMotionEvent === 'undefined') { setStatus("❌ Tu navegador no soporta DeviceMotionEvent."); return; } if (typeof DeviceMotionEvent.requestPermission === 'function') { DeviceMotionEvent.requestPermission() .then(response => { if (response === 'granted') { setStatus("✅ Sensor activado. Coloca el móvil sobre la carga."); window.addEventListener('devicemotion', motionHandler); } else { setStatus("❌ Permiso denegado: " + response); } }) .catch(err => setStatus("⚠️ Error: " + err)); } else { setStatus("✅ Sensor activado. Coloca el móvil sobre la carga."); window.addEventListener('devicemotion', motionHandler); } } function motionHandler(event) { const acc = event.accelerationIncludingGravity; const ts = event.timeStamp; if (!acc) return; if (lastTimestamp === null) { lastTimestamp = ts; return; } // Filtro pasa-alto para eliminar la gravedad gz = alpha * gz + (1 - alpha) * acc.z; const az = acc.z - gz; const dt = (ts - lastTimestamp) / 1000; lastTimestamp = ts; // Integramos solo si hay movimiento real if (Math.abs(az) > UMBRAL_ACEL) { velocidad += az * dt; } else { // desacelera suavemente si no hay movimiento velocidad *= 0.98; } // Guardar el pico máximo alcanzado const absVel = Math.abs(velocidad); if (absVel > vmax) { vmax = absVel; } // Si velocidad baja casi a cero, dejamos el valor máximo fijo if (absVel < VMIN_RESET) { velocidad = 0; } updateDisplay(); } startBtn.addEventListener('click', startMotion); resetBtn.addEventListener('click', resetValues); }); </script>

orr

<div id="encoder-motionis" style="font-family: Arial, sans-serif; text-align: center; background: #f5f8fa; padding: 30px;"> <h1 style="color:#007BFF;">Encoder de velocidad 📊</h1> <div style="font-size: 1.2em; margin: 6px 0;">Velocidad X: <span id="vx">0.00</span> m/s</div> <div style="font-size: 1.2em; margin: 6px 0;">Velocidad Y: <span id="vy">0.00</span> m/s</div> <div style="font-size: 1.2em; margin: 6px 0;">Velocidad Z: <span id="vz">0.00</span> m/s</div> <!-- vmax grande y muy visible --> <div style="font-size: 3rem; font-weight: 800; color: #FF4500; margin: 18px 0; line-height: 1;"> 🏁 <span id="vmax">0.00</span> m/s </div> <button id="startBtn" type="button" style="padding: 12px 22px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 10px; cursor: pointer; margin: 6px;">Iniciar</button> <button id="resetBtn" type="button" style="padding: 12px 22px; font-size: 1em; background: #6c757d; color: white; border: none; border-radius: 10px; cursor: pointer; margin: 6px;">Reiniciar</button> <div id="status" style="color:#555; margin-top: 12px; font-size: 0.95em;">⏸ Aún no iniciado</div> </div> <script type="text/javascript"> document.addEventListener('DOMContentLoaded', function () { // Estado const statusEl = document.getElementById('status'); const vxEl = document.getElementById('vx'); const vyEl = document.getElementById('vy'); const vzEl = document.getElementById('vz'); const vmaxEl = document.getElementById('vmax'); const startBtn = document.getElementById('startBtn'); const resetBtn = document.getElementById('resetBtn'); // Variables físicas let lastTs = null; let vx = 0, vy = 0, vz = 0; let vmax = 0; // Filtro pasa-alto para quitar gravedad cuando usamos accelerationIncludingGravity let gx = 0, gy = 0, gz = 0; const alpha = 0.8; // suavizado del filtro pasa-alto const ACC_THRESHOLD = 0.20; // m/s²: umbral para ignorar ruido const DECAY = 0.97; // reducción suave en reposo para frenar deriva const MIN_SPEED = 0.05; // por debajo de esto, fuerza a 0 let usingIncluding = null; // decidimos automáticamente qué campo usar en el primer evento function setStatus(msg){ statusEl.textContent = msg; console.log(msg); } function updateUI(){ vxEl.textContent = vx.toFixed(2); vyEl.textContent = vy.toFixed(2); vzEl.textContent = vz.toFixed(2); vmaxEl.textContent = vmax.toFixed(2); } function resetAll(){ lastTs = null; vx = vy = vz = 0; vmax = 0; gx = gy = gz = 0; usingIncluding = null; updateUI(); setStatus('🔄 Reiniciado'); } function startMotion(){ if (typeof DeviceMotionEvent === 'undefined'){ setStatus('❌ DeviceMotionEvent no soportado en este navegador.'); return; } // iOS pediría permiso; en Android normalmente no hace falta: if (typeof DeviceMotionEvent.requestPermission === 'function'){ DeviceMotionEvent.requestPermission() .then(r => { if (r === 'granted'){ setStatus('✅ Sensor activado. Coloca el móvil y realiza la repetición.'); window.addEventListener('devicemotion', onMotion, { passive: true }); } else { setStatus('❌ Permiso denegado: ' + r); } }) .catch(err => setStatus('⚠️ Error permiso: ' + err)); } else { setStatus('✅ Sensor activado. Coloca el móvil y realiza la repetición.'); window.addEventListener('devicemotion', onMotion, { passive: true }); } } function onMotion(ev){ // Elegimos la mejor fuente disponible AUTOMÁTICAMENTE en el 1er evento if (usingIncluding === null){ if (ev.acceleration && ev.acceleration.x !== null){ usingIncluding = false; // ya viene sin gravedad setStatus('📡 usando event.acceleration (sin gravedad)'); } else { usingIncluding = true; // usaremos includingGravity + filtro pasa-alto setStatus('📡 usando accelerationIncludingGravity + filtro'); } } const ts = ev.timeStamp; if (lastTs === null){ lastTs = ts; return; } const dt = (ts - lastTs) / 1000; lastTs = ts; if (dt <= 0 || dt > 1) return; // evita saltos extraños // Obtención de aceleraciones ax, ay, az en m/s² let ax, ay, az; if (!usingIncluding){ // Ya viene sin gravedad const a = ev.acceleration; if (!a) return; ax = a.x || 0; ay = a.y || 0; az = a.z || 0; } else { // Quitamos gravedad mediante filtro pasa-alto const ag = ev.accelerationIncludingGravity; if (!ag) return; gx = alpha * gx + (1 - alpha) * (ag.x || 0); gy = alpha * gy + (1 - alpha) * (ag.y || 0); gz = alpha * gz + (1 - alpha) * (ag.z || 0); ax = (ag.x || 0) - gx; ay = (ag.y || 0) - gy; az = (ag.z || 0) - gz; } // Integramos solo si supera umbral (ignorar micro-ruido) vx = (Math.abs(ax) > ACC_THRESHOLD) ? (vx + ax * dt) : (vx * DECAY); vy = (Math.abs(ay) > ACC_THRESHOLD) ? (vy + ay * dt) : (vy * DECAY); vz = (Math.abs(az) > ACC_THRESHOLD) ? (vz + az * dt) : (vz * DECAY); // Corte bajo para forzar a 0 si queda residuo if (Math.abs(vx) < MIN_SPEED) vx = 0; if (Math.abs(vy) < MIN_SPEED) vy = 0; if (Math.abs(vz) < MIN_SPEED) vz = 0; // Actualizamos vmax (pico en cualquier eje, valor absoluto) const maxAxis = Math.max(Math.abs(vx), Math.abs(vy), Math.abs(vz)); if (maxAxis > vmax) vmax = maxAxis; updateUI(); } startBtn.addEventListener('click', startMotion); resetBtn.addEventListener('click', resetAll); }); </script>